Typescript: Conditional types
Conditional types
Conditional types in TypeScript are super powerful, they allow us to create type functions. I'll show you.
Let's say we have 3 types: A
, B
and C
.
type A
type B
type C
TypeScripttype A
type B
type C
They could be anything, but let's say that A
is string
, B
is number
and C
is the union of A
and B
.
type A = string;
type B = number;
type C = A | B;
TypeScripttype A = string;
type B = number;
type C = A | B;
Now, we want to convert string
and number
to literal numeric representations.
string
should be 1
,
type NumberA = 1;
type NumberB = number;
type NumberC = 1 | number;
TypeScripttype NumberA = 1;
type NumberB = number;
type NumberC = 1 | number;
number
should be 2
, and anything else should be 0
.
type NumberA = 1;
type NumberB = 2;
type NumberC = 1 | 2;
TypeScripttype NumberA = 1;
type NumberB = 2;
type NumberC = 1 | 2;
If this was a function, you would simply use conditionals to drive the code. It would look something like this:
const ToNumber = (T) => (T === string ? 1 : T === number ? 2 : 0);
TypeScriptconst ToNumber = (T) => (T === string ? 1 : T === number ? 2 : 0);
That syntax doesn't work for types, but it's pretty close.
type ToNumber = (T) =>
T === string
? 1
: T === number
? 2
: 0
TypeScripttype ToNumber = (T) =>
T === string
? 1
: T === number
? 2
: 0
Instead of an arrow, we use equals.
type ToNumber(T) =
T === string
? 1
: T === number
? 2
: 0
TypeScripttype ToNumber(T) =
T === string
? 1
: T === number
? 2
: 0
Instead of parenthesis, we use angle brackets.
type ToNumber<T> =
T === string
? 1
: T === number
? 2
: 0
TypeScripttype ToNumber<T> =
T === string
? 1
: T === number
? 2
: 0
And instead of triple equals, we use extends.
type ToNumber<T> = T extends string ? 1 : T extends number ? 2 : 0;
TypeScripttype ToNumber<T> = T extends string ? 1 : T extends number ? 2 : 0;
See, we are not asking TypeScript if T
is equal to string
, what we're asking is if T
is a subset of string
.
That also includes literal string types, such as "abc"
.
type A = string
type B = number
type C = A | B
ToNumber<A> // -> 1
ToNumber<B> // -> 2
ToNumber<C> // -> 1 | 2
ToNumber<boolean> // -> 0
ToNumber<"abc"> // -> 1
TypeScripttype A = string
type B = number
type C = A | B
ToNumber<A> // -> 1
ToNumber<B> // -> 2
ToNumber<C> // -> 1 | 2
ToNumber<boolean> // -> 0
ToNumber<"abc"> // -> 1
Conclusion
References are below.
This article is part of my TypeScript Narrowing Series. You can read the full series for free on my blog.
Leave a like, have a great day, and I'll see you soon!