如何让函数参数推断Record类型中多对象字段的精确类型
问题:推断Record类型中对象字段的精确类型
我想要实现一个函数,使其能够推断传入Record类型中对象字段的精确类型。示例代码如下:
const exact = func({ foo: { a: 1, b: 2 } }) const _a: 1 = exact.foo.a const _b: 2 = exact.foo.b // FIXME: typeof b 为`number`,而非`2`
目前我已实现让1被正确推断,但无法推断2,请问该如何解决?
我目前的代码尝试:
type FIXME = number interface Thing<a extends number, b extends number> { a: a b: b } // prettier-ignore const x = <_ extends Record<keyof _, number>>(args: {[k in keyof _]: Thing<_[k],FIXME>}): {[k in keyof _]: Thing<_[k],FIXME>} => args
解决方案
你当前的问题在于用固定的FIXME = number约束了b的类型,导致TypeScript无法捕获其字面量类型。要让所有字段的精确类型被推断,需要让泛型完整捕获传入对象的结构,而非硬编码类型约束。
方案1:基于预定义Thing类型的实现
interface Thing<A extends number, B extends number> { a: A; b: B; } // 让泛型T直接匹配传入的对象结构,保留所有字面量类型信息 const func = <T extends Record<string, Thing<number, number>>>(args: T): T => args; // 测试验证 const exact = func({ foo: { a: 1, b: 2 } }); const _a: 1 = exact.foo.a; // 类型推断正确 const _b: 2 = exact.foo.b; // 现在类型为字面量2,而非宽泛的number
方案2:更通用的任意嵌套对象推断
如果不需要固定的Thing结构,希望支持任意嵌套对象的字面量类型推断,可以使用更灵活的写法:
const func = <T extends Record<string, Record<string, number>>>(args: T): T => args; // 测试验证 const exact = func({ foo: { a: 1, b: 2 }, bar: { c: 3, d: 4 } }); const _a: 1 = exact.foo.a; const _b: 2 = exact.foo.b; const _c: 3 = exact.bar.c; const _d: 4 = exact.bar.d;
原理说明
通过让泛型T直接捕获传入对象的完整结构,并且返回类型直接复用T,TypeScript会自动保留每个字段的字面量类型,而不会将其拓宽为number这类基础类型。
内容的提问来源于stack exchange,提问作者Jason Kuhrt
相关产品推荐
相关产品推荐

