Typescript Conditional Types: Use extends, infer, and keyof to create conditional logic in types.
TypeScript's Conditional Types provide a way to perform type-level computations using a ternary-like syntax.
By combining extends
, infer
, and keyof
, we can express complex type logic. Here's a breakdown:
1. Basic Conditional Types Syntax typescript
T extends U ? X : Y
If
T
is assignable toU
, the type resolves toX
; otherwise, it resolves toY
.
2. Using extends in Conditional Types
You can check if one type extends another:
type IsString<T> = T extends string ? true : false;type Test1 = IsString<string>; // truetype Test2 = IsString<number>; // false
3. Using infer to Extract Types
infer
allows you to extract types in conditional types, often within generic contexts like functions or arrays.
Example: Extract Return Type of a Function
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;type Fn = (x: number) => string;type Result = ReturnType<Fn>; // string
Example: Extract Array Element Type
type ElementType<T> = T extends (infer U)[] ? U : never;type ArrayOfNumbers = number[];type Result = ElementType<ArrayOfNumbers>; // number
4. Using keyof with Conditional Types
keyof
extracts the keys of a type, useful when working with object types.
Example: Conditional Type to Check for a Specific Property
type HasName<T> = 'name' extends keyof T ? true : false;type ObjWithName = { name: string; age: number };type ObjWithoutName = { age: number };type Test1 = HasName<ObjWithName>; // truetype Test2 = HasName<ObjWithoutName>; // false
5. Combining extends, infer, and keyof
You can combine all three to create powerful type utilities.
Example: Extract the Type of a Specific Property
type PropertyType<T, K extends keyof T> = T[K];type Person = { name: string; age: number };type NameType = PropertyType<Person, 'name'>; // string
Example: Deeply Nested Return Type Extraction
type DeepReturnType<T> =T extends (...args: any[]) => infer R? R extends (...args: any[]) => any? DeepReturnType<R>: R: never;type Fn1 = () => () => number;type Fn2 = () => () => () => string;type Result1 = DeepReturnType<Fn1>; // numbertype Result2 = DeepReturnType<Fn2>; // string
Summary
By combining extends
, infer
, and keyof
in TypeScript conditional types:
extends
checks subtype relations.infer
extracts and infers types.keyof
works with keys of object types.
These tools enable you to build highly flexible, type-safe utilities for complex type manipulations.