Explaining the Pick<Type, Keys> typescript challenge

Ikechi Michael
3 min readFeb 22, 2023

--

I found TypeScript challenges on GitHub when I wanted to improve my TypeScript skills. Before then, I knew basic typescript such as

const name: string = "John Doe";
const age: number = 100;

type Person = {
name: string;
age: number
}
const person: Person = { name, age }

const getPersonName = (person: Person) => person.name; // -? string

But I had not fully understood that one of typescript’s most powerful features is its ability to derive types from other types. E.g.

const a = { name: "John Doe" } as const
const b = { age: 25 } as const

const c = {
...a,
...b
} // -? { name: "John Doe", age: 25 }

In the above, we see that typescript knows that the type of c is { name: “John Doe”, age: 25 } because it can derive it from a combination of the types of a and b .

To assist with deriving types from other types, TypeScript exposes a few utility types, one of which is Pick<Type, Keys> , that helps us derive a new type that has only the keys we pick from a record type. e.g.

type Person = {
name: string;
age: number;
}

type AgelessPerson = Pick<Person, "name">

const john: Person = { name: "John Doe", age: 25 };
const tom: AgelessPerson = { name: "Tom" };

// @ts-expect-error
const jerry: AgelessPerson = { name: "Jerry", age: 30};
// throws error because `age` does not belong in type `AgelessPerson`

So Pick<Person, "name"> gives us a new type { name: string } which has the picked “name” key.

Our Challenge

The Pick<Type, Keys> challenge is to implement a MyPick<Type, Keys> type, which does exactly the same thing as Pick<Type, Keys> .

So we’re going to do that, and then explain the code to understand what is happening.

type MyPick<T, K extends keyof T> = { [key in K]: T[key] }

Generics in typescript are a way to tell typescript to keep track of specific parts of a type.

Here, our MyPick type has two generic parameters, T and K .

K extends keyof T gives us a constraint for what the type of K should be, and it also informs typescript about what type T can accept.

By using extending keyof T , our T can only be a Record type such as {} , { [key: string}: any } , and our K can only be keys of T .

This means that if we wrote something like:

MyPick<{ name: string }, "age"> // will throw an error

we will have an error thrown on "age" because it is not a keyof { name: string } .

Having written these constraints, we can now derive our new type:

{ [key in K]: T[key] }

This syntax lets us know our new type is a Record, and that every key in our new type is the values we supply for K , while the corresponding Record value will be T[key].

type MyPick<
T,
K extends keyof T
> = {
[key in K]: T[key]
}

And there you have it. The explanation of MyPick<T, K> , a reimplementation of the Pick<T, K> utility type.

--

--

Ikechi Michael

I’ve learned I don’t know anything. I've also learned that people will pay for what I know. Maybe that's why they never pay.