Photo by Ulysse Pointcheval on Unsplash
TypeScript: Type Predicate
When using Union, Type Predicate help you solve `Property X doesn't exist on type [...]`
Today, I have come across a concept new to me in TypeScript: Type Predicates.
Let's see what problem Type Predicates solve and when to use them.
For more information, you can check the official documentation here
The problem: unknown type at compile time ๐ฅ
Let's say you need to fill your car. Your car is either running on diesel or unleaded.
type Diesel = {
isDiesel: true,
}
type Unleaded = {
isUnleaded: true,
}
type Fuel = Unleaded | Diesel
function fillMyCar(fuel: Fuel){
if (fuel.isDiesel){
console.log("Filled with Diesel!")
} else if (fuel.isUnleaded){
console.log("Filled with Unleaded")
}
}
/* ๐ด Property 'isDiesel' does not exist on type 'Diesel | Unleaded'.
Property 'isDiesel' does not exist on type 'Unleaded'. */
/* ๐ด Property 'isUnleaded' does not exist on type 'Diesel | Unleaded'.
Property 'isUnleaded' does not exist on type 'Diesel'. */
Why do we encounter this error?
When using Union
in TypeScript, the compiler cannot know for sure the type of the object you are using until runtime.
If your car is unleaded, then the isDiesel
property doesn't exist on it!
Type Predicates
is a solution to this common problem.
Solution: Type Predicates ๐ฏ
A Type Predicate allows us to check and narrow the type of the argument at runtime
function isDiesel(fuel:Fuel):fuel is Diesel{
return true;
}
The Type Predicate resides in fuel is Diesel
.
It translates to:
if fuel is Diesel, then execute the code. Else, return false.
Great. Now we can refactor our previous code:
type Diesel = {
isDiesel: true,
}
type Unleaded = {
isUnleaded: true,
}
type Fuel = Unleaded | Diesel
function isDiesel(fuel:Fuel):fuel is Diesel{
return true;
}
function fillMyCar(fuel: Fuel){
if (isDiesel(fuel)){
console.log("Filled with Diesel!")
} else if (fuel.isUnleaded){
console.log("Filled with Unleaded")
}
}
โ๏ธ Note that Typescript is smart enough to realise that if it's not Diesel
, then it must be Unleaded
since we only have two types in the union!
That's pretty cool if you ask me.
Conclusion โ๏ธ
The goal of Type Predicates is to inform the compiler that we are checking the type at runtime and handling each case.
I am actually glad I came across this as I had encountered this issue multiple times in the past.
Today I learnt... Type Predicates ๐