Implement a type`DeepOmit`, Like Utility types [Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys), A type takes two arguments. Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.
In this medium-level challenge, you'll implement DeepOmit<T, S> which works like the built-in Omit utility type but supports dot-separated paths to omit deeply nested properties from an object type.
Implement a typeDeepOmit, Like Utility types Omit, A type takes two arguments.
For example:
type obj = {
person: {
name: string;
age: {
value: number
}
}
}
type test1 = DeepOmit<obj, 'person'> // {}
type test2 = DeepOmit<obj, 'person.name'> // { person: { age: { value: number } } }
type test3 = DeepOmit<obj, 'name'> // { person: { name: string; age: { value: number } } }
type test4 = DeepOmit<obj, 'person.age.value'> // { person: { name: string; age: {} } }Change the following code to make the test cases pass (no type check errors).
type obj = {
person: {
name: string
age: {
value: number
}
}
}
type cases = [
Expect<Equal<DeepOmit<obj, 'person'>, {}>>,
Expect<
Equal<DeepOmit<obj, 'person.name'>, { person: { age: { value: number } } }>
>,
Expect<Equal<DeepOmit<obj, 'name'>, obj>>,
Expect<
Equal<
DeepOmit<obj, 'person.age.value'>,
{ person: { name: string; age: {} } }
>
>,
]
Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.
One-time payment. Lifetime access.
type DeepOmit<T, S extends string> = {
[K in keyof T as K extends (S extends `${infer First}.${string}` ? First : S) ? never : K]:
S extends `${infer First}.${infer Rest}`
? K extends First
? DeepOmit<T[K], Rest>
: T[K]
: T[K]
}How it works:
K of Tas clause filters out keys: if the path S contains a dot (e.g., 'person.name'), we extract the first segment; if there is no dot, S itself is the key to omit. If K matches, it is mapped to never (removed)S is a dotted path like 'person.name', we check whether K matches the first segment (person). If so, we recursively apply DeepOmit<T[K], Rest> to dig deeper into the nested objectK does not match the first segment, or if S has no dots, we keep the value as T[K]DeepOmit<obj, 'person'> (removes the top-level key), DeepOmit<obj, 'person.name'> (removes a nested key), and DeepOmit<obj, 'name'> (no match at top level, so the object is unchanged)This challenge helps you understand recursive mapped types with key filtering and dot-path string parsing, and how to apply these concepts in real-world scenarios.
This challenge is originally from here.