Stav Alfi
Stav Alfi

Reputation: 13933

Implementing Pick type

While trying to implement Pick, I was not sure why the type WrongPick gives bad result with an |.

interface Todo {
  title: string
  description: string
  completed: boolean
}

type WrongPick<T, K> =  K extends keyof T ? {[P in K]: T[P]} : never

type wrong_result = WrongPick<Todo, 'title' | 'completed'>
// expected: { title: string ; completed: boolean }
// actual: { title: string } | { completed: boolean }

type CorrectPick<T, K extends keyof T> = {[P in K]: T[P]}

type correct_result = CorrectPick<Todo, 'title' | 'completed'>
// expected: { title: string ; completed: boolean }
// actual: { title: string ; completed: boolean }

Typescript Playground

Upvotes: 0

Views: 43

Answers (1)

tenshi
tenshi

Reputation: 26322

Because of distributive conditional types, WrongPick<Todo, "title" | "completed"> actually expands to

("title" extends keyof T ? { [P in "title"]: Todo[P] } : never) | ("completed" extends keyof T ? { [P in "completed"]: Todo[P] } : never)

which simplifies to

{ title: string } | { completed: boolean }

As described in the above link to the documentation, you can "turn it off" by wrapping both sides in tuples:

type WrongPick<T, K> =  [K] extends [keyof T] ? { [P in K]: T[P] } : never

Playground

Upvotes: 3

Related Questions