The instructions for this challenge are:
Implement the built-in
Omit<T, K>
generic without using it.Constructs a type by picking all properties from
T
and then removingK
Example code that should compile correctly is provided:
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyOmit<Todo, 'description' | 'title'>
const todo: TodoPreview = {
completed: false,
}
We start with the type:
type MyOmit<T, K> = any
From the example we know that K
is going to represent keys from T
. We can do this with keyof
to change our type
to:
type MyOmit<T, K extends keyof T> = any
We know that the eventual type will be an object. We also know that the object will only have keys from T
so we will
want to use keyof
again on the right-hand side of the expression. As we know the type of the keys of the resulting
object
we will be able to use
an index signature:
type MyOmit<T, K extends keyof T> = { [P in keyof T]: any }
The in
keyword here is used to constrain the index signature to only accept a key of T
. This is
a Mapped Type.
There are still two problems we need to solve:
- We aren’t omitting the values we are supposed to.
- We don’t maintain the types of the values in the object (can affect completion in editors).
The second issue is trivial to fix:
type MyOmit<T, K extends keyof T> = { [P in keyof T]: T[P] }
This change should be fairly readable if you have a Javascript background. In Typescript it’s referred to as value type and will allow you to customise the emitted value a little if you wish (we aren’t doing that here though).
The first issue requires us to reuse a technique from the first challenge: conditional types. We can test whether our
mapped type is in the omit specification K
. If it is then we can assign it to the empty set never
(in a mapped
type never
will filter the key out), if it is not then we simply use the mapped type (P
). This removes any keys in
K
from the emitted type, implementing the Omit type.
This gives us the eventual solution:
type MyOmit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P]
}