TypeScript中如何用泛型与三元运算符定义普通对象函数参数类型?
问题根源:分布式条件类型的特性
问题出在哪?
你的Test泛型触发了分布式条件类型——当泛型参数是联合类型时,TypeScript会自动把联合类型拆成单个成员,分别执行条件判断,再把结果重新合并成新的联合类型。
针对Test<'keyA' | 'keyB'>:
- 先对
'keyA'应用条件逻辑,得到{ keyA: 'test' } - 再对
'keyB'应用条件逻辑,得到{ keyB: 'test' } - 最终生成的类型是
{ keyA: 'test' } | { keyB: 'test' }
为什么变量赋值没问题?
{ keyA: 'test', keyB: 'test' }是这个联合类型的子类型——它同时满足联合中两个成员的结构,TypeScript允许将更具体的类型赋值给更宽泛的联合类型,因此变量obj不会报错。
为什么函数参数报错?
函数参数的类型是联合类型时,TypeScript会做严格的类型校验:它只能保证传入的参数是联合中的某一个成员,无法确定具体是哪一个。当你访问obj.keyA时,联合类型里的{ keyB: 'test' }并没有keyA属性,因此触发类型错误。
解决方案:阻止分布式条件类型
要让联合类型作为一个整体参与条件判断,只需把泛型参数用方括号包裹,破坏分布式条件类型的触发机制:
type Test<K extends string | {}> = [K] extends [string] ? { [key in K]: 'test' } : K; type Obj = Test<'keyA' | 'keyB'>; // 现在类型是 { keyA: 'test'; keyB: 'test' } const fn = (obj: Test<'keyA' | 'keyB'>) => { return obj.keyA; // 不再报错 }
这样'keyA' | 'keyB'会被当作一个整体判断是否属于string类型,此时key in K会遍历联合类型的所有成员,生成包含所有键的对象类型,而非联合类型。
内容的提问来源于stack exchange,提问作者lukebm
相关产品推荐
相关产品推荐

