TypeScript通用单属性提取函数的类型定义问题
TypeScript 通用单属性提取函数的类型错误修复
需求说明
需要实现一个通用函数,用于从对象中筛选提取单个属性。初始无类型版本如下:
function pickOnePropertyUntyped(data: any, key: any): any { return { [key]: data[key] } }
期望行为示例:
interface A { a: string; b: number; } const a: A = { a: 'a', b: 1 } const r = pickOnePropertyUntyped(a, 'a'); // 返回 {'a': 'a'}
尝试的带类型约束实现
我尝试实现了带类型约束的版本,该版本能正确限制输入为单个key,也能正确推断输出类型,但返回值的类型标记存在错误:
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never type NoUnion<Key> = [Key] extends [UnionToIntersection<Key>] ? Key : never; type PickOneProperty<T, P extends keyof T & string> = { [K in keyof T as K extends NoUnion<P> ? K : never]: T[K] } function pickOneProperty<T, K extends keyof T & string>( data: T, key: K, ): PickOneProperty<T, K> { return { [key]: data[key] } }
解决方案
方案1:类型断言快速修复
直接对返回值添加类型断言,让TypeScript确认返回值符合目标类型:
function pickOneProperty<T, K extends keyof T & string>( data: T, key: K, ): PickOneProperty<T, K> { return { [key]: data[key] } as PickOneProperty<T, K> }
方案2:简化类型定义
简化返回类型的定义,直接构造单属性对象类型,同时优化泛型约束位置,让类型推断更顺畅:
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never type NoUnion<Key> = [Key] extends [UnionToIntersection<Key>] ? Key : never; function pickOneProperty<T, K extends NoUnion<keyof T & string>>( data: T, key: K, ): { [P in K]: T[P] } { return { [key]: data[key] } as { [P in K]: T[P] } }
这里将K的约束直接放在泛型定义中,确保输入只能是单个key,返回类型{ [P in K]: T[P] }更直观,TypeScript能更好地匹配。
方案3:利用Object.assign避免断言
通过Object.assign创建对象,帮助TypeScript自动推断正确的返回类型,无需手动断言:
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never type NoUnion<Key> = [Key] extends [UnionToIntersection<Key>] ? Key : never; function pickOneProperty<T, K extends NoUnion<keyof T & string>>( data: T, key: K, ): { [P in K]: T[P] } { return Object.assign({}, { [key]: data[key] }) }
内容的提问来源于stack exchange,提问作者Lesiak
相关产品推荐
相关产品推荐

