What are Conditional Types?
Conditional types are a TypeScript feature introduced in version 2.8 that enable you to define types based on conditions. They allow you to express complex type relationships and create reusable type logic. Conditional types are defined using the extends
keyword and the ?
operator, making them highly versatile.
Basic Syntax
Let's start with the basic syntax of a conditional type:
type MyConditionalType<T> = T extends U ? X : Y;
-
T
is the type parameter we want to test. -
U
is the type we're checkingT
against. -
X
is the type thatMyConditionalType
evaluates to if the condition istrue
. -
Y
is the type thatMyConditionalType
evaluates to if the condition isfalse
.
Understanding the Condition
The condition in a conditional type can be any valid type operation or expression. Commonly used operations include keyof
, extends
, and infer
. Here's a breakdown of some common condition types:
-
keyof
: Checks if a type has a specific key. -
extends
: Tests if a type extends another type. -
infer
: Extracts a type from another type.
Basic Examples
Conditional Type with extends
type IsString<T> = T extends string ? true : false;
const a: IsString<"Hello"> = true; // true
const b: IsString<42> = false; // false
In this example, IsString<T>
checks if T
extends (is assignable to) the string
type. If so, it returns true
, otherwise false
.
keyof
and Index Signatures
type KeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
};
interface Person {
name: string;
age: number;
email: string;
}
type StringKeys = KeysOfType<Person, string>; // "name" | "email"
Here, KeysOfType<T, U>
generates a new type that contains keys from T
whose corresponding values extend U
. In our Person
interface, it extracts keys with values of type string
.
Advanced Examples
Mapping Union Types
type FilterByType<T, U> = T extends U ? T : never;
type OnlyStrings = FilterByType<string | number | boolean, string>; // "string"
This example creates a type that filters out all non-U
types from a union type T
.
Inferring Function Parameters
type FirstParam<T> = T extends (param1: infer P, ...args: any[]) => any ? P : never;
function greet(name: string, age: number) {
return `Hello, ${name}! You are ${age} years old.`;
}
type NameParam = FirstParam<typeof greet>; // string
Here, FirstParam<T>
extracts the type of the first parameter of a function. In this case, it infers string
from the greet
function.
Built-in Conditional Types
TypeScript provides several built-in conditional types that simplify common type operations.
Exclude
Exclude<T, U>
removes all types from T
that are assignable to U
.
type Excluded = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
Extract
Extract<T, U>
extracts all types from T
that are assignable to U
.
type Extracted = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
NonNullable
NonNullable<T>
removes null
and undefined
from T
.
type NotNullable = NonNullable<string | null | undefined>; // string
Top comments (0)