gpt4 book ai didi

typescript :在将可选类型与必需类型合并时创建并集而不是交集

转载 作者:搜寻专家 更新时间:2023-10-30 21:07:38 24 4
gpt4 key购买 nike

当可选属性和必需属性通过交集合并时,必需属性优先

type A = { who: string }
type B = { who?: string }
// $ExpectType {who:string}
type R = A & B

这可能会导致运行时错误,例如,在处理函数中的默认参数模式时

type Params = {
who: string
greeting: string
}

const defaults: Params = {
greeting: 'Hello',
who: 'Johny 5',
}

function greeting(params: Partial<Params>){
// $ExpectType Params
const merged = {...defaults, ...params}

return `${merged.greeting.toUpperCase()} ${merged.who} !`
}

// @throws - TypeError: Cannot read property 'toUpperCase' of undefined
greeting({greeting:undefined, who: 'Chuck'})

问题:

我所描述的是 TS 编译器的行为方式,问题是如何创建映射类型,将交集解析为并集

所以像这样:

type SafeMerge<A,B>=....

// $ExpectType {greeting?: string | undefined, who?: string | undefined }
type Result = SafeMerge<Params, Partial<Params>>

混合类型示例:

// $ExpectType {one?: number | undefined, two: string, three: boolean }
type Result = SafeMerge<{one: number, two:string}, {one?: number, three: boolean}>

最佳答案

得到一个合并类型,它是两种类型的合并,每个属性都是可能性的并集。我们可以在两种构成类型的键上使用映射类型:

type SafeMerge<T, U> = {
[P in keyof T | keyof U] :
| (T extends Partial<Record<P, any>> ? T[P] : never)
| (U extends Partial<Record<P, any>> ? U[P] : never)
}
type Result = SafeMerge<{one: number, two:string }, {one?: number, three: boolean }>
// Result:
// type Result = {
// one: number | undefined;
// two: string;
// three: boolean;
// }

Play

上述解决方案的问题是我们失去了键的可选性(还有只读性,这对于这个用例来说可能不太重要)。同态映射类型保留修饰符,但不幸的是我们不能在这里使用修饰符,因为我们并不真正适契约(Contract)态映射类型的任何模式( { [P in keyof T] : T[P] }{[P in K]: T[P] } ,其中 K 是带有 K extends keyof T 的类型参数,参见 HereHere )。

我们可以提取可选键并使用两种映射类型,一种用于任何可选键(键在至少一个成分中是可选的),另一种用于必需键:

type OptionalPropertyOf<T> = Exclude<{
[K in keyof T]: T extends Record<K, T[K]>
? never
: K
}[keyof T], undefined>

type SafeMerge<T, U> = {
[P in OptionalPropertyOf<T> | OptionalPropertyOf<U>]?:
| (T extends Partial<Record<P, any>> ? T[P] : never)
| (U extends Partial<Record<P, any>> ? U[P] : never)
} & {
[P in Exclude<keyof T | keyof U, OptionalPropertyOf<T> | OptionalPropertyOf<U>>]:
| (T extends Partial<Record<P, any>> ? T[P] : never)
| (U extends Partial<Record<P, any>> ? U[P] : never)
}

type Result = SafeMerge<{one: number, two:string, three: number}, {one?: number, three: boolean}>
// Result:
// type Result = {
// one?: number | undefined;
// } & {
// two: string;
// three: number | boolean;
// }

type Id<T> = {} & { [P in keyof T]: T[P] }
type FlattenedResult = Id<SafeMerge<{one: number, two:string, three: number }, {one?: number, three: boolean}>>
// type FlattenedResult = {
// one?: number | undefined;
// two: string;
// three: number | boolean;
// }

Play

我们可以选择 Id像我在上面的示例中所做的那样展平交点,但这是可选的。

关于 typescript :在将可选类型与必需类型合并时创建并集而不是交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57474241/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com