如何避免TypeScript条件映射类型结果中混入{}类型?
TypeScript 类型工具优化问题
原始定义与问题
我们定义了如下接口:
interface A { a: string b: string c?: number d?: number }
同时定义了类型B<T>,目的是将T中类型为string的键设为可选,类型为number的键设为必填:
type B<T> = { [K in keyof T as T[K] extends (number|undefined) ? K : never]-?: T[K] } & { [K in keyof T as T[K] extends (string|undefined) ? K : never]+?: T[K] } /* 正常生成的类型: type B<A> = { c: number; d: number; } & { a?: string | undefined; b?: string | undefined; } */
但当接口仅包含其中一种类型时(比如仅含string类型键的A1):
interface A1 { a: string b: string } /* 生成的类型变为: type B<A1> = {} & { a?: string | undefined; b?: string | undefined; } */
这会导致非预期类型可以被赋值给B<A1>,例如:
const b: B<A1> = "We don't want this to happen." // 此处本该报错,但现在不会
解决方案
修改B<T>类型,通过条件类型判断是否存在某一类键,避免生成包含{}的交叉类型:
// 提取T中属于number/undefined类型的键 type RequiredNumberKeys<T> = { [K in keyof T]: T[K] extends (number | undefined) ? K : never }[keyof T] // 提取T中属于string/undefined类型的键 type OptionalStringKeys<T> = { [K in keyof T]: T[K] extends (string | undefined) ? K : never }[keyof T] type B<T> = // 若没有number类型的键,直接返回可选string键的类型 RequiredNumberKeys<T> extends never ? { [K in OptionalStringKeys<T>]?: T[K] } // 若没有string类型的键,直接返回必填number键的类型 : OptionalStringKeys<T> extends never ? { [K in RequiredNumberKeys<T>]-?: T[K] } // 两种键都存在时,返回交叉类型 : { [K in RequiredNumberKeys<T>]-?: T[K] } & { [K in OptionalStringKeys<T>]?: T[K] }
修改后,B<A1>会直接生成为:
{ a?: string | undefined; b?: string | undefined; }
此时再执行const b: B<A1> = "We don't want this to happen."就会触发TypeScript的类型错误,符合预期。
内容的提问来源于stack exchange,提问作者asnaeb
相关产品推荐
相关产品推荐

