如何通过点符号排除对象键,实现TypeScript递归泛型转换
实现
ValueOrStringExcludeNestedKeys<T, K>泛型类型 需求是实现一个TypeScript泛型,递归地为对象的所有基本类型属性(包括嵌套子属性)添加string联合类型,但需排除K中以点符号指定的路径集合对应的属性,这些排除的属性保留原有类型不变。
示例场景
type Values = { a: { b: { c: string; d: number; }; e: string; }; f: number; g: number; h: { i: number; } }; type Result = ValueOrStringExcludeNestedKeys<Values, 'a.b.c' | 'f'>; /* 期望结果: type Result = { a: { b: { c: string; // 保持原类型不变 d: number | string; }; e: string; // string | string 等价于 string }; f: number; // 保持原类型不变 g: number | string; h: { i: number | string; }; } */
实现思路
要完成这个泛型,核心是处理路径匹配和递归遍历对象结构:
- 拆分点分隔的路径字符串为层级元组,方便逐层匹配嵌套属性
- 递归遍历对象的每个属性,判断当前属性的路径是否属于排除列表
- 对基本类型属性,若不在排除路径则添加
string联合类型;对象类型则继续递归处理
完整代码实现
// 辅助类型:将点分隔的路径字符串拆分为元组 type SplitPath<S extends string> = S extends `${infer Head}.${infer Tail}` ? [Head, ...SplitPath<Tail>] : [S]; // 核心泛型实现 type ValueOrStringExcludeNestedKeys<T, K extends string, CurrentPath extends string[] = []> = T extends object ? { [Key in keyof T]: // 拼接当前路径,判断是否在排除列表中 `${[...CurrentPath, Key extends string ? Key : never].join('.')}` extends K ? T[Key] // 路径匹配,保留原类型 : ValueOrStringExcludeNestedKeys<T[Key], K, [...CurrentPath, Key extends string ? Key : never]> } : // 基本类型,若不在排除路径则添加string联合类型 `${CurrentPath.join('.')}` extends K ? T : T | string;
代码解释
- SplitPath:递归拆分路径字符串,比如
SplitPath<'a.b.c'>会得到['a','b','c'],用于后续层级匹配(内部逻辑支撑路径拼接判断)。 - ValueOrStringExcludeNestedKeys:
- 若当前类型是对象,遍历每个属性,拼接当前路径后判断是否属于排除路径:是则保留原类型,否则递归处理子属性
- 若当前是基本类型,判断当前路径是否在排除列表:是则保留原类型,否则返回
原类型 | string
测试验证
用示例中的Values类型测试:
type TestResult = ValueOrStringExcludeNestedKeys<Values, 'a.b.c' | 'f'>; // 输出结果与预期完全一致
内容的提问来源于stack exchange,提问作者A.A
相关产品推荐
相关产品推荐

