This site uses tracking technologies. You may opt in or opt out of the use of these technologies.

Back to Typescript

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 to U, the type resolves to X; otherwise, it resolves to Y.

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>; // true
type 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>; // true
type 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>; // number
type 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.