Maximilian: Yet another TypeScript feature
that can help with deriving types from other types
is the conditional types feature.
And this is a feature which is particularly useful
for building utility types, helper types, you could say,
as I'll show you in this first example.
Let's say you have a situation
where in your application in different places
in that application, you're dealing with array types,
arrays of numbers, strings, objects, doesn't matter.
And you now wanna build a helper type
that makes it easy to extract the type
of the elements that are in the array,
so not the array type as a whole,
but just the type of elements in the array.
So if you, for example, have a string array type like this,
so I'm simply mapping the built-in string array type
to my custom type named StringArray,
and you then want to get the ElementType
of the elements in that array,
you could of course do so
by using StringArray[number] like that.
That's what you learned earlier in the course,
and that's not the conditional type feature.
But as a result, ElementType here would be string.
Now let's say you want to build a generic utility type
that you can use on all kinds of arrays
to extract the information about the types
that is managed by those arrays.
So that's stored as elements in the arrays.
You could achieve this by making ElementType generic,
and by trying to use this syntax.
However this fails because TypeScript doesn't know
whether T will really be an array.
Of course you could convince TypeScript
by adding a constraint here,
telling it that T will always extend some array type.
So an array full of anything,
where we don't care about the actual type
of value in there,
but it will be some array full of anything.
So in that case,
you could use ElementType on the string array here,
and example one would be string.
So now you would have a helper ElementType
which can be used on any array type
to extract information about the type
of value stored in the array,
like we're doing it here.
But one potential problem in a more complex applications
is that you can't use ElementType on anything
that's not an array.
So for example, if I had some text here,
so not a type but some value,
the text 'hello', could also be a variable of course,
and I then try to use ElementType
on the type of this text variable.
So on the type of the value that's stored in
that text variable, I would get an error
that my string here is not an array.
And of course the same would be true
if this were a number.
In that case I would get an error
that a number is not an array,
which of course makes sense.
And this of course is not necessarily a problem.
I mean we built a utility type ElementType here,
which can only be used on arrays,
that's not necessarily bad or a problem.
But you could build an even more generic helper type
which allows you to extract information from other types
by using this conditional type feature I want to show you.
So, for that I'll actually comment out this code,
and add a new type here,
which I'll again name ElementType
or GetElementType to make it clear
that this is kind of a utility type.
And now here I'll again make it generic,
but I won't add that constraint
that it only works on arrays.
Instead, we can make this a conditional type
by adding a ternary expression-like syntax
on the right side of the equal side here.
And again, what I'm about to write
will look like a ternary expression,
but we are in TypeScript world here,
we are defining a type,
so it will be a TypeScript feature
just using a syntax that looks like ternary expressions
in JavaScript, because the syntax looks like this.
We can take a look at the concrete type we'll get
when we use GetElementType on some other type,
and check whether it extends, any array.
So whether it is some array.
Now here I'm not defining a constraint
because I'm not using this here
between the angle brackets,
instead this is the syntax for writing a condition
in TypeScript, it is kind of writing equals, you could say,
using extends here.
I'm checking whether the type I'm getting
is an array full of anything.
Then you add a question mark and then
after the question mark, you define the type
that should be returned, you could say,
by GetElementType if this condition is met.
So if the type we're using GetElementType on
is some array.
And in my case here, that will be this type here
where I use this special syntax for extracting the type
of the elements in that array.
And I know that I'm working
with an array here due to this condition.
Now just as in ternary expressions in JavaScript,
you then also must add a colon to define an else case.
What should be the type returned by GetElementType
if this condition here is not met?
And that can be anything of your choice in the end.
For example, it could be T, so the unchanged type,
it could be never, to kind of make it clear
that this will not be a value
that should be returned by this type,
whatever you want.
Here I'll go for never.
And this now, allows me to use
GetElementType on my string array like this.
And in that case example one will be string.
So GetElementType will yield the type of the values
in that array, which in this case is string of course.
But if I bring back this example with the text here,
I can now use that for my second example,
still with GetElementType,
and pass in the type of this text variable,
which is number of course.
And example two will be never.
Now it would be number if it would just return T here
in that else case.
In that case example two would be number,
we would keep the original type,
but depending on how your utility type should work,
you can of course also change this to something like never,
so that example two is never
and is essentially a type we can't work with thereafter.
And you might wonder why you would want a feature like this.
Well, obviously these are advanced and to be honest,
niche features which you might not need all the time
and in very many projects.
You might especially not need features like this
when building applications with TypeScript.
But when building libraries or frameworks,
anything like this with TypeScript,
you sometimes might need features like this
to be able to work with the different kinds
of values your library might need to deal with
when being used by our developers.
That's one of the primary reasons
for why features like this exist,
which of course always makes it a bit hard
to show you good examples that are easy to grasp
and make sense at the same time.
But it hopefully is clear
how this conditional type feature here works.
It is essentially a ternary expression in TypeScript land.
And what it does, that it allows you to define a type
that will actually be a different type
depending on whether this condition here is met, or not.