Advanced Conditional and Mapped Types

1. Welcome and Icebreaker:

  • If you could transform or filter any set of data in your life, what would you change?

2. Outline the Session:

  • We’ll revisit conditional and mapped types for more complex transformations.
  • Learning Outcomes: Understand how to create advanced type logic using conditional and mapped types.
  • Let’s get advanced!

3. Concept Explanation:

  • Conditional Types can be nested and combined for complex logic.
  • Mapped Types can use modifiers and remap keys.
  • You can create utility types like Partial, Required, Readonly, Pick, Omit, and more.
  • Example:
    type MyPartial<T> = { [K in keyof T]?: T[K] };
    type MyOmit<T, K extends keyof T> = { [P in keyof T as Exclude<P, K>]: T[P] };
    

4. Live Coding Demonstration:

type User = { id: number; name: string; email?: string };
type RequiredUser = { [K in keyof User]-?: User[K] };
type UserWithoutEmail = Omit<User, "email">;

type IsString<T> = T extends string ? true : false;
type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] };
type StringProps = OnlyStrings<User>; // { name: string; email?: string }

// Nested conditional types
type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};

const partialUser: DeepPartial<User> = { name: "Alice" };

5. Tasks:

  • Short Exercise:
    1. Write a mapped type Optional<T> that makes all properties optional.
    2. Write a conditional type IsArray<T> that is true if T is an array, otherwise false.
    3. Create a type that picks only the string properties from an object type.