TypeScript多参数泛型函数如何从指定参数推导类型
解决方案
你可以通过降低第二个参数的泛型推导优先级实现需求,TypeScript 4.7及以上版本内置了NoInfer工具类型,用来标记某个位置的泛型参数不参与类型推导,仅做后续类型校验:
type TypeA<T extends string> = Record<T, unknown>; type TypeB<T> = { array: T[] }; // 仅修改泛型T在第二个参数的引用,包裹NoInfer function fn<T extends string>(a: TypeA<T>, b: TypeB<NoInfer<T>>): void {}
如果使用的是4.7以下版本的TypeScript,可以自行实现NoInfer类型:
// 自定义NoInfer实现 type NoInfer<T> = [T][T extends any ? 0 : never]; type TypeA<T extends string> = Record<T, unknown>; type TypeB<T> = { array: T[] }; function fn<T extends string>(a: TypeA<T>, b: TypeB<NoInfer<T>>): void {}
原理说明
默认情况下TypeScript会从泛型参数出现的所有位置共同推导类型,你的原始写法中第二个参数的array: ["attr1"]更早收窄了T的类型为"attr1",导致第一个参数的attr2属性不符合类型校验。
给第二个参数的T包裹NoInfer后,TypeScript会优先从第一个参数推导T的类型为所有对象键的联合类型"attr1" | "attr2",再用推导完成的T去校验第二个参数的数组元素是否属于T的子集,既符合你的推导预期,也能正常校验第二个参数的数组元素合法性。
修改后你原来的调用代码不会再抛出错误,如果你在第二个参数的数组中填写第一个参数不存在的键,TypeScript仍然会正常提示类型错误。
内容的提问来源于stack exchange,提问作者Mateus Pires
相关产品推荐
相关产品推荐

