Hi people! How you've been? Is it everything alright?
Today let's talk about some interesting pattern in Typescript and I will blow your mind! This pattern is called Discriminated Type Union
or Discriminated Union Type
.
Before I deep dive on this patter, we need to undestand the problem.
I will write some code with you:
type PokemonState = {
status: "Loading" | "Success" | "Error";
pokemon?: { name: number; sprite: string; hp: number };
error?: { message: string };
};
So I created a type called PokemonState
, which contains status
, pokemon
with some properties and error
with a message.
Now notice, that pokemon
and error
, depends of the status, so it will be can be undefined
.
If the status is Loading
, just return the status.
If the status is Success
, just return the pokemon.
If the status is Error
, just return the error message.
So Let's create a function with a switch on state:
const printPokemon = (pokemonState: PokemonState) => {
switch (pokemonState.status) {
case "Loading":
console.log(pokemonState.status);
break;
case "Success":
console.log(pokemonState.pokemon.name, pokemonState.pokemon.sprite, pokemonState.pokemon.hp);
break;
case "Error":
console.log(pokemonState.error.message);
break;
default:
break;
}
};
But I will show what I'm seeing on the VSCode with typescript validation:
And heeeey! Typescript type safe validation is here!
How I said, pokemon
and error
, depends of state
. We can create some logic on our function validating each status and define if we have our properties. But it's not the best solution.
But now enters ouw pattern, called Dicriminated Type Union
.
Let's refact our type State on three types based on our state.
type PokemonLoading = {
status: "Loading";
};
type PokemonSuccessState = {
status: "Success";
pokemon: { name: number; sprite: string; hp: number };
};
type PokemonErrorState = {
status: "Error";
error: { message: string };
};
Now we can remove the ?
can be undefined property on each state.
And Let's create our Union Type:
type PokemonNewState =
| PokemonLoading
| PokemonSuccessState
| PokemonErrorState;
and change the parameter type on our function:
const printPokemon = (pokemonState: PokemonNewState) => {
switch (pokemonState.status) {
case "Loading":
console.log(pokemonState.status);
break;
case "Success":
console.log(pokemonState.pokemon.name, pokemonState.pokemon.sprite, pokemonState.pokemon.hp);
break;
case "Error":
console.log(pokemonState.error.message);
break;
default:
break;
}
};
Now is we applied the pattern on Discriminated Type Union. Now we can understand why this pattern is called with union type.
With a common property, we can separate in another types and make typescript undestand that is type safe.
I love this pattern and blow my mind how typescript can validate and turn our code more clean and understandable.
So that's it!
I hope that you enjoyed and liked of this tip/pattern on typescript.
Thank you so much. And stay well always! ❤️
Contacts:
Youtube: https://www.youtube.com/@ueharakevin/
Linkedin: https://www.linkedin.com/in/kevin-uehara/
Instagram: https://www.instagram.com/uehara_kevin/
Twitter: https://twitter.com/ueharaDev
Github: https://github.com/kevinuehara
Top comments (0)