Conditional types in TypeScript allow you to create types that depend on a condition. They are a powerful feature that can make your type definitions more flexible and expressive. This topic will cover the basics of conditional types, provide practical examples, and include exercises to help you understand and apply this concept.

Key Concepts

  1. Basic Syntax: The basic syntax of a conditional type is T extends U ? X : Y, where:

    • T is the type you are checking.
    • U is the type you are comparing against.
    • X is the type returned if T extends U.
    • Y is the type returned if T does not extend U.
  2. Usage: Conditional types are often used to create more specific types based on certain conditions.

  3. Distributive Conditional Types: When conditional types are applied to a union type, they are distributed over each member of the union.

Practical Examples

Example 1: Basic Conditional Type

type IsString<T> = T extends string ? "Yes" : "No";

// Usage
type A = IsString<string>; // "Yes"
type B = IsString<number>; // "No"

Explanation:

  • IsString is a conditional type that checks if T extends string.
  • If T is a string, it returns "Yes", otherwise it returns "No".

Example 2: Conditional Type with Union

type ToArray<T> = T extends any ? T[] : never;

// Usage
type A = ToArray<string>; // string[]
type B = ToArray<number>; // number[]
type C = ToArray<string | number>; // string[] | number[]

Explanation:

  • ToArray is a conditional type that converts a type T to an array of T.
  • If T is a union type, the conditional type is distributed over each member of the union.

Example 3: Nested Conditional Types

type TypeName<T> = 
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

// Usage
type A = TypeName<string>; // "string"
type B = TypeName<() => void>; // "function"
type C = TypeName<{}>; // "object"

Explanation:

  • TypeName is a nested conditional type that returns a string representation of the type T.
  • It checks multiple conditions to determine the type of T.

Exercises

Exercise 1: Create a conditional type IsArray<T> that checks if a type T is an array.

type IsArray<T> = T extends any[] ? "Array" : "Not Array";

// Test cases
type Test1 = IsArray<string[]>; // "Array"
type Test2 = IsArray<number>; // "Not Array"
type Test3 = IsArray<[number, string]>; // "Array"

Exercise 2: Create a conditional type Flatten<T> that flattens an array type T.

type Flatten<T> = T extends (infer U)[] ? U : T;

// Test cases
type Test1 = Flatten<string[]>; // string
type Test2 = Flatten<number[][]>; // number[]
type Test3 = Flatten<number>; // number

Exercise 3: Create a conditional type ReturnType<T> that extracts the return type of a function type T.

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// Test cases
type Test1 = ReturnType<() => string>; // string
type Test2 = ReturnType<(x: number) => boolean>; // boolean
type Test3 = ReturnType<() => void>; // void

Common Mistakes and Tips

  • Mistake: Forgetting that conditional types distribute over union types.

    • Tip: Always consider how your conditional type will behave with union types.
  • Mistake: Using conditional types without understanding the extends keyword.

    • Tip: Make sure you understand how extends works in TypeScript before using conditional types.
  • Mistake: Overcomplicating type definitions with nested conditional types.

    • Tip: Keep your type definitions as simple as possible and only use nested conditional types when necessary.

Conclusion

Conditional types are a powerful feature in TypeScript that allow you to create types based on conditions. They can make your type definitions more flexible and expressive. By understanding the basic syntax and usage of conditional types, you can leverage them to create more dynamic and adaptable types in your TypeScript code. Practice with the provided exercises to reinforce your understanding and apply conditional types effectively.

© Copyright 2024. All rights reserved