Implement a generic `PartialByKeys<T, K>` which takes two type argument `T` and `K`. Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.
In this medium-level challenge, you'll implement a generic PartialByKeys<T, K> that makes only the specified keys K optional while leaving the rest of the properties required.
Implement a generic PartialByKeys<T, K> which takes two type argument T and K.
K specify the set of properties of T that should set to be optional. When K is not provided, it should make all properties optional just like the normal Partial<T>.
For example
interface User {
name: string
age: number
address: string
}
type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }Change the following code to make the test cases pass (no type check errors).
interface User {
name: string
age: number
address: string
}
interface UserPartialName {
name?: string
age: number
address: string
}
interface UserPartialNameAndAge {
name?: string
age?: number
address: string
}
type cases = [
Expect<Equal<PartialByKeys<User, 'name'>, UserPartialName>>,
Expect<Equal<PartialByKeys<User, 'name' | 'age'>, UserPartialNameAndAge>>,
Expect<Equal<PartialByKeys<User>, Partial<User>>>,
// @ts-expect-error
Expect<Equal<PartialByKeys<User, 'name' | 'unknown'>, UserPartialName>>,
]
Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.
One-time payment. Lifetime access.
type Merge<T> = {
[K in keyof T]: T[K]
}
type PartialByKeys<T, K extends keyof T = keyof T> = Merge<
Omit<T, K> & Partial<Pick<T, K>>
>How it works:
K extends keyof T = keyof T constrains K to valid keys of T and defaults to all keys when K is not provided, making it behave like Partial<T>.Omit<T, K> produces the portion of T without the keys we want to make optional, preserving them as required.Partial<Pick<T, K>> picks only the specified keys and makes them optional.& combines both portions, but intersected types can look messy, so the Merge helper flattens the result into a single clean object type.As an alternative, you can write this without relying on built-in utility types:
type PartialByKeys<T, K extends keyof T = keyof T> = Merge<
{ [P in K]?: T[P] } & { [P in Exclude<keyof T, K>]: T[P] }
>This challenge helps you understand intersection type flattening and selective property modification, and how to apply these concepts in real-world scenarios.
This challenge is originally from here.