Mapped Types

1. Welcome and Icebreaker:

  • If you could transform every item in your house in one go, what would you change?

2. Outline the Session:

  • We’ll learn about mapped types in TypeScript: how to transform existing types into new types.
  • Learning Outcomes: Understand how to use mapped types to create flexible and reusable type transformations.
  • Let’s map it out!

3. Concept Explanation:

  • Mapped Types use the in keyword to create new types by transforming each property in an existing type.
  • Syntax:
    type Readonly<T> = {
      readonly [P in keyof T]: T[P];
    };
    
  • Useful for creating utility types like Partial, Readonly, Pick, and Record.
  • You can use modifiers like readonly? and -? to add or remove optionality.

4. Live Coding Demonstration:

type User = {
  id: number;
  name: string;
  email: string;
};

// Make all properties readonly
type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

const user: ReadonlyUser = { id: 1, name: "Alice", email: "alice@example.com" };
// user.id = 2; // Error: Cannot assign to 'id' because it is a read-only property.

// Make all properties optional
type PartialUser = {
  [K in keyof User]?: User[K];
};

const partial: PartialUser = { name: "Bob" };

// Remove optionality
type RequiredUser = {
  [K in keyof PartialUser]-?: PartialUser[K];
};

const required: RequiredUser = { id: 1, name: "Alice", email: undefined };

// Map to new property names
type PrefixedUser = {
  [K in keyof User as `user_${string & K}`]: User[K];
};

const prefixed: PrefixedUser = {
  user_id: 1,
  user_name: "Alice",
  user_email: "alice@example.com"
};
console.log(prefixed);

5. Tasks:

  • Short Exercise:
    1. Write a mapped type Nullable<T> that makes all properties of T nullable.
    2. Write a mapped type UppercaseKeys<T> that transforms all property names to uppercase (hint: use as Uppercase<K>).
    3. Create a type User and use your mapped types on it.