← All tasksTypeScript · Middle

Mapped types: MyPick, MyReadonly, MyOmit

Write your own versions of the utility types without the built-in Pick, Readonly, Omit and Exclude.

MyPick<T, K> keeps only the keys K of T (and rejects a key that T does not have), MyReadonly<T> makes every field readonly on the first level, and MyOmit<T, K> removes the keys K while keeping the other fields optional where they were.

Tests (5)

Type tests are checked by the TypeScript compiler in strict mode. Expect<Equal<A, B>> passes when the types match exactly, and // @ts-expect-error passes when the next line does not compile. The first run downloads the compiler, so it takes a few seconds.

  1. types
    interface Todo { title: string; done: boolean; tags: string[] }
    type _ = Expect<Equal<MyPick<Todo, 'title' | 'done'>, { title: string; done: boolean }>>;
  2. types
    interface Todo { title: string; done: boolean }
    // @ts-expect-error - 'nope' is not a key of Todo
    type _ = MyPick<Todo, 'nope'>;
  3. types
    interface Todo { title: string; meta: { done: boolean } }
    type _ = Expect<Equal<MyReadonly<Todo>, { readonly title: string; readonly meta: { done: boolean } }>>;
  4. types
    interface Todo { title: string; done: boolean; tags: string[] }
    type _ = Expect<Equal<MyOmit<Todo, 'tags'>, { title: string; done: boolean }>>;
  5. types
    interface Todo { title: string; done?: boolean }
    type _ = Expect<Equal<MyOmit<Todo, 'title'>, { done?: boolean }>>;