TypeScript Type Challenge Pick Walkthrough
The goal of the challenge is to reimplement the built in Pick generic type that exists in TypeScript, without using Pick
itself.
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00004-easy-pick/README.md
Watch the video
An example case
Given the following TypeScript:
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
Given the interface Todo
above, we need to create a generic type MyPick
that takes the type (Todo
) and a union of the properties that we wish to pick from it. The base code would look something like:
type MyPick<T, K> = ?
Approach
If we were creating a function in JavaScript to do a similar job, we'd want to loop over everything in K
and construct a new object with each entry from K
as a key. We'd set that key value equal to T[i]
to reference the original value of T for that key.
We can do something similar in TypeScript types with mapped types. The syntax for a mapped type is:
type MyPick<T, K> = {
[Property in K]: T[Property]
}
Where property is bound to each entry in our K
type union.
The solution
The above creates a new type from the existing type T
, with only the keys from K
in it, as it loops over the entries in K
only. However it doesn't work as TypeScript has no guarantee that the type K is a union type. For example:
MyPick<Todo, number>
Would not through any TypeScript errors as both T
and K
are types, Todo
and number
respectively. Clearly we need to restrict the type of K to be a union type of keys that exist on T.
type MyPick<T, K extends keyof T> = {
[Property in K]: T[Property]
}
This means that even if K is a union, if it includes properties that do not exist on T, it will result in a compiler error.