Implement `PickByType<T, U>` so it keeps only the properties whose value type is assignable to `U`. The rejected keys must disappear entirely, not survive as `never`.
01
Try the puzzle yourself
Par 3
Puzzle
pick-by-type.ts
interface Mixed {
id: number
name: string
active: boolean
score: number
}
type PickByType<T, U> = ???
Stroke 1 of 3Not run yet
Replace ??? — your solution is checked against the cases below. Tab indents; press Escape then Tab to move focus out.
Checks
4
PickByType<Mixed, number>—
→ { id: number; score: number }
PickByType<Mixed, string>—
→ { name: string }
PickByType<Mixed, symbol>—
→ {}
PickByType<{ a: string }, string>—
→ { a: string }
How a check is judged Exact type equality, not assignability — an intersection is not the same as the flattened object.
How everyone did
Fewer than 5 people have solved this one so far. The distribution appears once there is enough of a sample to mean anything.
type PickByType<T, U> = {
[K inkeyof T as T[K] extends U ? K : never]: T[K]
}
The common wrong answer
type PickByType<T, U> = {
[K inkeyof T]: T[K] extends U ? T[K] : never
}
The filtering happens on the value side, so every key survives — the rejected ones just hold `never`. `PickByType<Mixed, number>` becomes `{ id: number; name: never; active: never; score: number }`, which is a very different type from the one asked for, and a nearly unusable one.
Line by line
as T[K] extends U ? K : never
The `as` clause rewrites each key as the mapping runs. Here the rewrite is conditional: keep the key unchanged when the value matches, or rename it to `never` when it does not.
never
A key of type `never` cannot exist, so TypeScript omits the property rather than creating an impossible one. That quiet rule is what turns key remapping into a filter.
Takeaway
Filtering an object type happens in the key clause, never in the value. `as ... : never` is the only way to make a property genuinely disappear.