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 CTypeScripttype A
type B
type CThey 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
: 0TypeScripttype ToNumber = (T) =>
T === string
? 1
: T === number
? 2
: 0Instead of an arrow, we use equals.
type ToNumber(T) =
T === string
? 1
: T === number
? 2
: 0TypeScripttype ToNumber(T) =
T === string
? 1
: T === number
? 2
: 0Instead of parenthesis, we use angle brackets.
type ToNumber<T> =
T === string
? 1
: T === number
? 2
: 0TypeScripttype ToNumber<T> =
T === string
? 1
: T === number
? 2
: 0And 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'>; // -> 1TypeScripttype 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!