如何让TypeScript函数接收泛型输入并返回同键异值类型对象
解决方案:精确映射A的子集到B的对应子集
问题核心
你遇到的核心问题是泛型约束不够严格:T extends A允许T包含A以外的额外属性,导致TypeScript无法确定keyof T的所有键都存在于B中。而Partial<A>的问题在于返回类型无法精确匹配传入的属性集合,只能返回所有属性可选的类型。
正确实现方式
我们需要将泛型T约束为仅包含A的属性子集,让TypeScript明确keyof T的每个键都同时存在于A和B中。以下是两种可行方案:
方案一:子集泛型约束
type A = { foo: number bar: number } type B = { foo: string bar: string } function f<T extends Pick<A, keyof T>>(input: T): { [K in keyof T]: B[K] } { const res = {} as { [K in keyof T]: B[K] }; // 示例实现:将数字转为字符串 for (const key in input) { res[key] = input[key].toString(); } return res; }
方案二:键集泛型约束
如果你希望更明确地指定传入的键范围,可以直接约束键的集合:
function f<K extends keyof A>(input: Pick<A, K>): Pick<B, K> { const res = {} as Pick<B, K>; for (const key in input) { res[key] = input[key].toString(); } return res; }
效果验证
两种方案都能实现你想要的精确类型推断:
const a = f({}); // 类型:{} const b = f({foo: 1}); // 类型:{foo: string} const c = f({bar: 2}); // 类型:{bar: string} const d = f({foo:1, bar:2}); // 类型:{foo: string, bar: string}
原理说明
Pick<A, keyof T>:确保T的所有键都来自A,排除了额外属性的可能性,让TypeScript确认keyof T的每个键都能索引B。{ [K in keyof T]: B[K] }:遍历T的所有键,将对应的值类型替换为B中同键的类型,实现精确映射。- 方案二中的
Pick<B, K>是上述映射类型的简写,效果完全一致。
简化技巧(可选)
如果A和B结构高度相似(仅值类型不同),可以定义通用映射类型来简化代码:
type MapToB<T extends Partial<A>> = { [K in keyof T]: B[K] }; function f<T extends Pick<A, keyof T>>(input: T): MapToB<T> { // 实现代码同上 }
内容的提问来源于stack exchange,提问作者Gbox4
相关产品推荐
相关产品推荐

