如何让含Readonly的可变参泛型函数保留字面量类型推断?
解决方案
要让可变参数函数保留传入对象字面量的键和值字面量类型,需要调整泛型约束的写法,避免TypeScript自动拓宽字面量类型为string。
问题根源
原写法中T extends Array<Readonly<Record<string, string>>>会让TypeScript将每个对象字面量的值自动拓宽为string类型,而非保留原始的字面量(比如"hello")。这是因为数组约束Array<X>会触发类型拓宽,将字面量类型提升到其基础类型。
正确声明方式
将泛型约束改为只读数组类型,让TypeScript对每个数组元素进行精确的字面量类型推断:
function foo2<T extends readonly Readonly<Record<string, string>>[]>(...args: T): void { // 函数逻辑 }
效果验证
调用该函数时,TypeScript会精确推断每个参数的完整字面量类型:
foo2({a: 'hello'}, {b: 'world'}); // T 被推断为:readonly [{ readonly a: "hello"; }, { readonly b: "world"; }]
原理说明
使用readonly ...[]作为泛型约束时,TypeScript会启用更严格的类型推断规则,不会将对象字面量的值自动拓宽为string,而是保留其原始的字面量类型。同时每个参数通过Readonly<Record<string, string>>约束确保是只读的键值对对象。
另一种可选写法
如果需要更灵活的类型检查,也可以用重载+条件类型的方式,确保每个参数符合要求的同时保留字面量:
// 类型推断用的重载签名 function foo2<T extends readonly any[]>(...args: T): T[number] extends Readonly<Record<string, string>> ? void : never; // 实现签名 function foo2(...args: readonly Readonly<Record<string, string>>[]): void { // 函数逻辑 }
这种写法会在编译期检查每个参数是否符合Readonly<Record<string, string>>的约束,同时保留精确的字面量类型推断。
内容的提问来源于stack exchange,提问作者JHH
相关产品推荐
相关产品推荐

