不使用大量重载实现Typescript嵌套对象属性路径访问的类型推导
TypeScript嵌套对象路径访问函数无重载实现方案
需求说明
实现嵌套对象属性路径访问函数的类型推导,满足两个核心要求:
- 支持传入任意层级的属性键,自动返回对应属性值的正确类型
- 传入非法属性键时直接抛出类型错误
原有逐层级编写函数重载的方案会出现「重载爆炸」问题,无法适配任意层级的访问需求。
实现代码
首先实现你提到的元组Tail类型,再通过递归类型实现深度取值推导,不需要任何手动重载:
// 元组Tail类型:返回去掉第一个元素后的剩余元组 type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never; // 深度取值类型:传入对象T和路径元组P,返回最终路径对应的属性类型 type PathValue<T, P extends PropertyKey[]> = P extends [infer K extends PropertyKey, ...infer Rest extends PropertyKey[]] ? K extends keyof T ? Rest extends [] ? T[K] : PathValue<T[K], Rest> : never : never; // 路径访问函数实现 function get<T extends object, P extends PropertyKey[]>( obj: T, // 约束参数:空路径、非法路径都会被约束为never,触发类型报错 ...keys: P extends [] ? never : PathValue<T, P> extends never ? never : P ): PathValue<T, P> { // 运行时逻辑可根据需求自行实现,此处为简化示例 return keys.reduce((current, key) => (current as any)[key], obj) as any; }
测试验证
interface TestObject { person: { firstName: string; lastName: string; address: { country: string; city: string; street: string; } } id: string; } const t: TestObject = {} as any; // 合法路径:类型自动推导正确 const result1 = get(t, 'person', 'address'); // result1类型:{ country: string; city: string; street: string; } const result2 = get(t, 'id'); // result2类型:string const result3 = get(t, 'person', 'address', 'city'); // result3类型:string // 非法路径:直接触发类型错误 const error1 = get(t, 'id', ''); // 报错:类型“["id", ""]”的参数不能赋给类型“never”的参数。ts(2345) const error2 = get(t, 'person', 'notExistKey'); // 报错:类型“["person", "notExistKey"]”的参数不能赋给类型“never”的参数。ts(2345)
说明
该实现依赖TypeScript 4.0及以上版本提供的剩余参数泛型推导、可变元组类型、递归条件类型能力,可支持任意层级的属性访问,完全避免了手动编写重载的问题。
内容的提问来源于stack exchange,提问作者Georgy Kalinchuk
相关产品推荐
相关产品推荐

