TypeScript Conditional Types (original) (raw)
Last Updated : 24 Jan, 2025
In TypeScript, conditional types enable developers to create types that depend on a condition, allowing for more dynamic and flexible type definitions.
- They follow the syntax T extends U ? X : Y, meaning if type T is assignable to type U, the type resolves to X; otherwise, it resolves to Y.
- Conditional types are particularly useful for creating utility types and for advanced type manipulations, enhancing code reusability and type safety. JavaScript `
type IsString = T extends string ? 'Yes' : 'No';
type Test1 = IsString; type Test2 = IsString;
console.log('Test1:', 'Yes'); console.log('Test2:', 'No');
`
- The IsString type alias uses a conditional type to check if a type T extends the string.
- If T is assignable to string, it resolves to 'Yes'; otherwise, it resolves to 'No'.
- Test1 is evaluated as 'Yes' because the string extends the string.
- Test2 is evaluated as 'No' because the number does not extend the string.
**Output:
**Test1: Yes
**Test2: No
JavaScript `
type Num = T extends number[] ? number : (T extends string[] ? string : never)
// Return num const num: Num<number[]> = 4;
// Return invalid const stringnum: Num = "7";
console.log(num, stringnum);
`
Conditional Type Constraints
Conditional type constraints allow defining constraints on generic types within conditional types, enabling dynamic and precise type handling.
JavaScript `
type CheckNum = T extends number ? T : never;
type NumbersOnly<T extends any[]> = { [K in keyof T]: CheckNum<T[K]>; };
const num: NumbersOnly<[4, 5, 6, 8]> = [4, 5, 6, 8]; const invalid: NumbersOnly<[4, 6, "7"]> = [4, 6, "7"];
`
- CheckNum ensures only numbers are retained; other types resolve to never.
- NumbersOnly applies CheckNum to each array element, filtering non-numbers.
**Output:
Type '"7"' is not assignable to type 'never'.
Inferring Within Conditional Types
This feature extracts and utilizes types within a conditional type definition, enabling precise transformations.
JavaScript `
type ElementType = T extends (infer U)[] ? U : never;
const numbers: number[] = [1, 2, 3]; const element: ElementType = numbers[0]; const invalidElement: ElementType = "string";
`
- ElementType extracts element types from arrays using the infer keyword.
- element correctly resolves to number; assigning a string is invalid.
**Output:
Type 'string' is not assignable to type 'number'.
Distributive Conditional Types
These types distribute over unions, applying conditional logic to each union member individually.
JavaScript `
type Colors = 'red' | 'blue' | 'green';
type ColorClassMap = { red: 'danger'; blue: 'primary'; green: 'success'; };
type MapColorsToClasses = T extends keyof ColorClassMap ? { [K in T]: ColorClassMap[T] } : never;
const redClass: MapColorsToClasses = { red: 'danger' }; const invalidClass: MapColorsToClasses = { yellow: 'warning' };
`
- MapColorsToClasses checks if T matches a key in ColorClassMap, mapping it accordingly.
- Invalid colors like 'yellow' are rejected because they do not exist in ColorClassMap.
**Output:
Type '{ yellow: "warning"; }' is not assignable to type 'never'.
Best Practices of Using TypeScript Conditional Types
- Use conditional types to create flexible, reusable type definitions.
- Combine conditional types with generics for enhanced adaptability.
- Utilize the infer keyword for type inference in complex scenarios.