- One of the more powerful features
that you're going to use in TypeScript
that I absolutely love is called the discriminated union,
or you may hear it called the discriminating union.
And essentially it's a union
that allows you to determine which part of the union
you're in based on some specific field or flag.
To figure out why you want this and what this is,
let's take a quick look at this code for a second.
We have a type which is a user API response.
This response can either be a success or an error.
And in the case that we have an error,
we're going to populate this error message with a message.
And in the case that we have a success,
we're gonna populate this data with an ID and a name
for the user that we just tried to query for.
Now in order to make sure our type works fine in both cases,
we need to make sure our data is optional
and our error message is optional,
because when our status is error,
we're not going to have any data at all,
and when our status is success,
we're not going to have any error message at all.
But I know for a fact that when my status is successful,
I will always have data.
And when my status is an error,
I will always have an error message.
So this leads to some interesting code,
because as I have this written,
data and error message are always optional no matter what.
So even when I check for a successful response,
I'm getting an error in TypeScript
because according to my type, my data could be undefined,
even though I know for a fact,
if I have a successful status, my data should be there.
Same thing with my error message.
I know if I have an unsuccessful status,
I know my error message should be there.
So the way we get around this problem
is by using a discriminated union.
The best way to think about that
is breaking our response into all the different permutations
we know are possible.
So we know the error status is possible
and the success status is possible.
So let's create two different types of responses.
The first one is going to be a success response.
And in that case, if we look at our code,
I know my status here is going to be success,
so I know it's just going to be
the hard coded string of success.
And then I know that I'm going to have my data,
so I'll copy this over, but I'm not gonna make it optional.
If I have a successful status,
I know that my data's gonna be there.
Now let's copy this down.
This is going to be for our error response.
Our status is going to be an error every single time
no matter what.
And instead of having a data,
we're gonna have an error message,
and this will no longer be optional.
So now I've created two different types.
One for what happens when I have a successful response,
and one for what happens when I have an error response.
So instead of trying to combine these together
into one complicated thing
that has a bunch of optional parameters,
I've broken them out into two specific different types.
Then what I can do is for my overall general type,
I know I'm going to be in one of these two scenarios,
so I can just use a union.
So I can say that we have our success response,
or we're gonna have our error response just like that.
And now as you can see,
this is just a combination of one of those two.
And also by just doing that,
you'll notice immediately all of these errors we had
in this function have gone away.
And that's because of the power
of these discriminated unions.
So the way you can know that you're using
a discriminated union is generally,
you're going to have some type of field which is different
between all of your different types.
So in our case, our status field is different.
So if we have a status of success,
we will always be in this particular type.
If our status is error,
we will always be in this particular type.
You'll very often see this with like,
different key values for example,
for like, statuses or something like that.
Now if we check for a status of success,
we know that the type of our data here for our response
is always going to be a successful response.
You can see it has changed the type to a success response,
because that is the only one of our keys in this union
that has a successful status.
While down here where we don't have a successful status,
you can see our response is set to an error response.
'Cause of our two options, this one is the only one
that does not have a status of success.
And now my data is automatically a required field,
so I know it's always gonna be there
and I don't have to do any weird if checks
to determine if it's there.
Same thing with my error message down here.
Now the important thing to understand about this
is you can only use literal values
when you're trying to do a discriminated union.
So if I were to try to say that this is a string,
and my status down here is a number,
this will no longer work.
Even if I do this like, typeof,
my status is equal to string,
and if I spell all of that properly,
you'll notice it still doesn't actually discriminately
unionize this for me.
And that's because it only works with literal values,
so the fact that these are strings versus numbers,
that doesn't work,
it only works with those literal values of like,
strings, numbers and so on.
That's perfectly okay because most places
that you want to use a discriminated union,
you're going to have different things,
such as a status or some other key where you have
a bunch of different types that this thing can be.
And very often you'll see this inside of a switch statement.
So for example, we're going to switch on our status,
and then we'll have a case in particular
where it's an error.
And then inside of here, if I try to get my information,
you'll see I only have access
to an error message in a status.
And that's because my error status is what's being used,
since I made sure to check for that error right there.