Execute Program

Advanced TypeScript: Partial Is a Mapped Type

Welcome to the Partial Is a Mapped Type lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • Now that we've seen mapped types, we can revisit the Partial utility type. Partial isn't a special part of the TypeScript compiler! It's a regular mapped type that we can define ourselves if we want to.

  • (We'll name our type OurPartial to avoid conflicting with the built-in Partial type.)

  • >
    type OurPartial<T> = {
    [P in keyof T]?: T[P];
    };

    type User = {
    email: string
    age: number
    };
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    const user: OurPartial<User> = {
    email: 'amir@example.com',
    };
    user;
    Result:
    {email: 'amir@example.com'}Pass Icon
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    const user: OurPartial<User> = {
    age: 36,
    };
    user;
    Result:
    {age: 36}Pass Icon
  • There are three important things happening in this type.

  • First, it's generic. Instead of referencing a specific type like User, the OurPartial type works with any object type. If we write OurPartial<{name: string, age: number}>, then OurPartial maps over the properties "name" and "age".

  • Second, OurPartial doesn't change the individual properties' types. It leaves them all as T[P]. The original User type has email: string, so OurPartial<User> also has an email property, and it's also a string.

  • Third, OurPartial makes the properties optional with the ? syntax: [P in keyof T]?: T[P]. The original User had email: string, so OurPartial<User> has email?: string.

  • At first, the syntax in [P in keyof T]?: T[P] may look strange. But it's the same optional property syntax that we've seen before, like email?: string. Here, the property name is [P in keyof T] instead of email, and the property type is T[P] instead of string.

  • Many utility types are implemented as mapped types. For example, we might want a Nullable type that makes all properties nullable, rather than making them optional. The process here is similar to OurPartial, except that we union the existing type with null. Unlike Partial, we don't need to use the optional property syntax (propertyName?: SomeType).

  • Here's a code problem:

    Sometimes we want a Nullable<T> utility type that makes every object property nullable. For example, if T has a number property, then Nullable<T> should have the same property, but with the type number | null. Finish the partially-written Nullable type below.

    type Nullable<T> = {
    [K in keyof T]: T[K] | null
    };
    type Company = {
    name: string
    yearFounded: number
    };

    const company1: Nullable<Company> = {name: 'Shure', yearFounded: null};
    const company2: Nullable<Company> = {name: null, yearFounded: 1925};

    /* We pull the properties back out to make sure your types are correct. */
    const name: string | null = company1.name;
    const yearFounded: number | null = company1.yearFounded;

    [name, yearFounded];
    Goal:
    ['Shure', null]
    Yours:
    ['Shure', null]Pass Icon