TypeScript如何实现泛型函数value参数类型依赖key参数值
问题原因
当前写法无法实现类型约束的核心原因:
- 写法
typeof T[key]本身不符合TS类型语法:typeof仅能对值空间的变量做类型提取,无法直接操作泛型类型参数。 - 仅声明泛型
T时,入参key的类型会被推导为所有keyof T的联合类型,对应的value类型会被推导为T所有属性值的联合类型,TS无法根据单次调用传入的单个具体key值,收窄value的匹配类型。
修复方案
新增一个继承自keyof T的泛型参数K,专门捕获调用时传入key的具体字面量类型,再将value的类型声明为T[K]即可实现联动约束:
const fn = <T, K extends keyof T>({ key, value }: { key: K; value: T[K]; }) => { return undefined; }; type Obj = { keyA: { propertyFromA: string; }; keyB: { propertyFromB: string; }; }; // 错误传参会触发类型校验 fn<Obj, "keyA">({ key: "keyA", value: { propertyFromB: "string" } // TS抛出类型错误,不符合{propertyFromA: string}约束 }); // 正确传参校验通过 fn<Obj, "keyA">({ key: "keyA", value: { propertyFromA: "string" } });
注意:非柯里化的写法如果只传第一个泛型参数fn<Obj>(...),TS不会自动推导第二个泛型K,会退化为之前的联合类型校验失效问题,因此要么手动传入K的具体类型,要么用柯里化写法让TS自动推导。
推导优化
如果不想每次调用都手动传入第二个泛型参数K,可以用柯里化写法提前绑定目标类型T,TS会自动根据后续传入的key值推导K的具体类型,无需手动标注:
const fn = <T>() => <K extends keyof T>({ key, value }: { key: K; value: T[K]; }) => { return undefined; }; type Obj = { keyA: { propertyFromA: string; }; keyB: { propertyFromB: string; }; }; // 提前绑定Obj类型 const useObjFn = fn<Obj>(); // 自动做类型联动校验 useObjFn({ key: "keyA", value: { propertyFromB: "string" } // 自动抛出类型错误 }); useObjFn({ key: "keyB", value: { propertyFromB: "string" } // 校验通过 });
内容的提问来源于stack exchange,提问作者Rashomon
相关产品推荐
相关产品推荐

