beraliv

Pick type under the hood in TypeScript

Example of Pick use
1type MyPick<T, Keys> = any; // implementation
2
3type Post = {
4 title: string;
5 description: string | undefined;
6 author: string;
7};
8
9type Step1 = MyPick<Post, "title" | "description">;
10type Step2 = { title: Post["title"]; description: Post["description"] };
11type Result = { title: string; description: string | undefined };

First challenge is Pick

It's usually used when you need to declare the type which is based on another type. And you know in advance which keys are included.

Iteration over an object

First, you need to iterate over an object T. Usually Mapped Types are used in this case:

Example of Mapped Types
1type MappedType<T> = {
2 [Key in keyof T]: T[Key];
3};
  • keyof T gets the keys from the object type T
  • in is for iteration over the keys
  • Key is a key itself
  • T[Key] is a value for a specified Key

Second, to iterate over the part of an object, we need to specify Keys to iterate over:

Iteration over Keys
1type MappedType<T, Keys> = {
2 [Key in Keys]: T[Key];
3};

But with this you have 2 errors:

  1. Type 'Keys' is not assignable to type 'string | number | symbol'
  2. Type 'Key' cannot be used to index type 'T'

Both errors are connected with the rules of the iteration:

  1. Key can be string, number or symbol
  2. We cannot call T[Key] if Key doesn't exist in T

If rule 2 is true, rule 1 will be true as existing keys are one of the specified types. To iterate over the existing keys, we need to apply Generic Constrains using extends keyword.

This way, if we specify non-existing key, TypeScript will throw an error We cannot call T[Key] if Key doesn't exist in T so we're safe now ✅

Solution
1type MyPick<T, Keys extends keyof T> = {
2 [Key in Keys]: T[Key];
3};

Check out the solution in Playground – https://tsplay.dev/mZbKem ⭐️

typescript
Alexey Berezin profile image

Written by Alexey Berezin who loves London 🏴󠁧󠁢󠁥󠁮󠁧󠁿, players ⏯ and TypeScript 🦺 Follow me on Twitter