TypeScript实现获取对象所有嵌套键路径(含数组索引)的类型
实现TypeScript的DeepKeys类型:包含嵌套对象与数组索引的键路径
完全可以实现你需要的DeepKeys类型,既能获取所有嵌套键路径,支持两种数组索引格式(.${number}和[${number}]),还能排除数组的内置方法(如push、pop)。以下是具体实现:
类型定义
// 提取数组的元素类型 type ArrayElement<T> = T extends (infer U)[] ? U : never; // 判断是否为数组类型 type IsArray<T> = T extends any[] ? true : false; // 核心DeepKeys类型 type DeepKeys<T> = T extends object ? { [K in keyof T as K extends string | number ? K : never]: | `${K}` | (IsArray<T[K]> extends true ? | `${K}.${number}` | `${K}[${number}]` | `${K}.${number}.${DeepKeys<ArrayElement<T[K]>>}` | `${K}[${number}].${DeepKeys<ArrayElement<T[K]>>}` : `${K}.${DeepKeys<T[K]>}`) }[keyof T] : never;
工作原理
- ArrayElement
: 专门用于提取数组的元素类型,比如对于 typeof person.hobbies(数组类型),它会返回内部对象类型{name: string}。 - IsArray
: 用于分支判断,区分当前属性值是数组还是普通对象。 - DeepKeys
: - 仅对对象类型生效,非对象类型直接返回
never。 - 遍历对象的每个键
K,仅保留字符串或数字类型的键(排除symbol类型键)。 - 首先包含当前键本身(如顶层的
"name"、"hobbies")。 - 如果当前键对应的值是数组:
- 生成两种数组索引格式的路径:
"hobbies.${number}"和"hobbies[${number}]"。 - 递归处理数组元素的键路径,分别拼接两种索引前缀,得到嵌套路径(如
"hobbies.${number}.name"和"hobbies[${number}].name")。
- 生成两种数组索引格式的路径:
- 如果是普通对象,递归处理嵌套键,用
.拼接路径(如"address.street")。
- 仅对对象类型生效,非对象类型直接返回
验证示例
const person = { name: 'Jim', address: { street: '1234 Some Street', city: 'Some City', state: 'Some State' }, hobbies: [ { name: 'Sports' } ] } type RESULT = DeepKeys<typeof person>;
此时RESULT的类型完全符合你的期望:
"name" | "address" | "address.street" | "address.city" | "address.state" | "hobbies" | "hobbies.${number}" | "hobbies[${number}]" | "hobbies.${number}.name" | "hobbies[${number}].name"
该实现不会生成hobbies.push这类无效路径,因为我们没有遍历数组的内置方法键,而是直接针对数组元素的嵌套结构生成路径。
内容的提问来源于stack exchange,提问作者Alex Johnson
相关产品推荐
相关产品推荐

