跳到主要内容

PartialsByKeys

介绍

实现一个通用的PartialByKeys<T, K>,它接收两个类型参数TK

K指定应设置为可选的T的属性集。当没有提供K时,它就和普通的Partial<T>一样使所有属性都是可选的。 例如:

ts
interface User {
name: string
age: number
address: string
}
type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }
ts
interface User {
name: string
age: number
address: string
}
type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }
View on GitHub

起点

ts
/* _____________ Your Code Here _____________ */
 
type PartialByKeys<T, K> = any
 
/* _____________ Test Cases _____________ */
 
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>>,
Type 'false' does not satisfy the constraint 'true'.2344Type 'false' does not satisfy the constraint 'true'.
Expect<Equal<PartialByKeys<User, 'name' | 'age'>, UserPartialNameAndAge>>,
Type 'false' does not satisfy the constraint 'true'.2344Type 'false' does not satisfy the constraint 'true'.
Expect<Equal<PartialByKeys<User>, Partial<User>>>,
Type 'false' does not satisfy the constraint 'true'.
Generic type 'PartialByKeys' requires 2 type argument(s).
2344
2314
Type 'false' does not satisfy the constraint 'true'.
Generic type 'PartialByKeys' requires 2 type argument(s).
// @ts-expect-error
Expect<Equal<PartialByKeys<User, 'name' | 'unknown'>, UserPartialName>>,
]
 
ts
/* _____________ Your Code Here _____________ */
 
type PartialByKeys<T, K> = any
 
/* _____________ Test Cases _____________ */
 
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>>,
Type 'false' does not satisfy the constraint 'true'.2344Type 'false' does not satisfy the constraint 'true'.
Expect<Equal<PartialByKeys<User, 'name' | 'age'>, UserPartialNameAndAge>>,
Type 'false' does not satisfy the constraint 'true'.2344Type 'false' does not satisfy the constraint 'true'.
Expect<Equal<PartialByKeys<User>, Partial<User>>>,
Type 'false' does not satisfy the constraint 'true'.
Generic type 'PartialByKeys' requires 2 type argument(s).
2344
2314
Type 'false' does not satisfy the constraint 'true'.
Generic type 'PartialByKeys' requires 2 type argument(s).
// @ts-expect-error
Expect<Equal<PartialByKeys<User, 'name' | 'unknown'>, UserPartialName>>,
]
 
take the challenge

解决方案

Spoiler warning // Click to reveal answer
ts
type PartialByKeys<T, K = never> = {
[P in keyof T as P extends K ? P : never]?: T[P]
} & {
[P in keyof T as P extends K ? never : P]: T[P]
}
 
/**
* 存在的问题: 可选属性的结果会是一个联合类型: 例如, name?: string | undefined
* under strictNullChecks, TypeScript will tell us they’re potentially undefined.
* 所以, 我们需要解决undefined的问题. 所以下文中IntersectionToObj的作用是?
*/
 
ts
type PartialByKeys<T, K = never> = {
[P in keyof T as P extends K ? P : never]?: T[P]
} & {
[P in keyof T as P extends K ? never : P]: T[P]
}
 
/**
* 存在的问题: 可选属性的结果会是一个联合类型: 例如, name?: string | undefined
* under strictNullChecks, TypeScript will tell us they’re potentially undefined.
* 所以, 我们需要解决undefined的问题. 所以下文中IntersectionToObj的作用是?
*/
 
ts
// most popular
type PartialByKeys<T extends {}, U = keyof T> =
Omit<Partial<Pick<T, U & keyof T>> & Omit<T, U & keyof T>, never>;
 
ts
// most popular
type PartialByKeys<T extends {}, U = keyof T> =
Omit<Partial<Pick<T, U & keyof T>> & Omit<T, U & keyof T>, never>;
 
ts
// most popular
type IntersectionToObj<T> = {
[K in keyof T]: T[K]
}
type PartialByKeys<T , K = any> = IntersectionToObj<{
[P in keyof T as P extends K ? P : never]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}>
 
ts
// most popular
type IntersectionToObj<T> = {
[K in keyof T]: T[K]
}
type PartialByKeys<T , K = any> = IntersectionToObj<{
[P in keyof T as P extends K ? P : never]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}>
 
ts
// deepseek
 
type PartialByKeys<T, K extends keyof T = keyof T> =
Omit<T, K> & Partial<Pick<T,K>> extends infer O
? {[P in keyof O]: O[P]}
: never;
 
 
ts
// deepseek
 
type PartialByKeys<T, K extends keyof T = keyof T> =
Omit<T, K> & Partial<Pick<T,K>> extends infer O
? {[P in keyof O]: O[P]}
: never;
 
 
view more solutions