如何让TypeScript自动推导元组参数类型 无需as const实现Lodash at类函数
解决方案
可以实现,核心是利用TypeScript 5.0引入的const泛型修饰符,让编译器自动把传入的路径数组推导为字面量元组,无需用户手动加as const。
修改后的完整代码
仅需要调整函数的泛型声明,原有路径匹配的类型逻辑不需要改动:
type PropertyAtPath<T, Path extends readonly any[]> = Path extends [] ? T : Path extends readonly [infer First, ...infer Rest] ? First extends keyof T ? PropertyAtPath<T[First], Rest> : undefined : unknown; type At<T, Paths extends ReadonlyArray<ReadonlyArray<any>>> = { [I in keyof Paths]: Paths[I] extends readonly any[] ? PropertyAtPath<T, Paths[I]> : never; }; // 仅在泛型Paths前加const修饰符即可 declare function at<T, const Paths extends ReadonlyArray<ReadonlyArray<any>>>( object: T, ...paths: Paths ): At<T, Paths>;
效果验证
const obj = { key1: '字符串值', key2: { key3: 1234 } }; // 无需加as const,直接调用即可正确推导类型 const result = at(obj, ['key1'], ['key2', 'key3']); // result的类型自动推导为:[string, number]
原理解释
- 默认情况下TypeScript会把传入的数组字面量推导为可变的普通数组类型(比如
['key1']会被推导为string[]),无法匹配路径需要的字面量元组类型,所以原来的实现必须要用户手动加as const把数组转为只读字面量元组。 - TypeScript 5.0新增的
const泛型修饰符,作用就是让编译器在推导泛型参数类型时,直接按照字面量常量的规则推导,效果等价于用户在所有入参前加了as const,无需修改调用侧代码。
低版本TS兼容方案
如果你的项目TS版本低于5.0,可以通过写函数重载的方式支持有限个数的路径参数,无需const修饰符:
// 重载1:支持1个路径 declare function at<T, P1 extends readonly PropertyKey[]>(obj: T, path1: P1): [PropertyAtPath<T, P1>] // 重载2:支持2个路径 declare function at<T, P1 extends readonly PropertyKey[], P2 extends readonly PropertyKey[]>(obj: T, path1: P1, path2: P2): [PropertyAtPath<T, P1>, PropertyAtPath<T, P2>] // 可根据业务需要继续扩展更多重载,支持更多路径参数
这种方案的缺点是需要手动写重载覆盖你需要支持的最大路径个数,无法支持任意个数的路径参数。
内容的提问来源于stack exchange,提问作者Eric Simonton
相关产品推荐
相关产品推荐

