如何递归创建TypeScript类型对象,返回嵌套键路径字符串
实现支持嵌套属性路径的类型安全字段生成工具
在Angular项目中使用第三方表格组件时,组件的field属性接收字符串值,而表格行类型由Swagger Codegen自动生成,导致字段名无法获得类型校验。原方案通过Proxy生成与类型结构一致的对象,返回属性键名作为字符串,但仅支持平级属性,无法处理嵌套结构的完整路径(如subrow.firstSubrowColumn无法返回"subrow.firstSubrowColumn")。
下面给出递归实现的完整方案:
递归类型定义
修改类型系统,支持递归生成嵌套结构的类型约束:
// 提取非null/undefined的键 type NonNullableKeys<T> = { [K in keyof T]: T[K] extends null | undefined ? never : K; }[keyof T]; // 递归生成属性路径类型:如果是对象(非数组、非基本类型)则递归,否则为字符串类型 type PropertiesOf<T> = { [K in NonNullableKeys<T>]: T[K] extends Record<string, any> ? T[K] extends any[] ? string // 数组类型直接返回字符串(字段路径为数组属性名本身) : PropertiesOf<T[K]> : string; };
递归Proxy实现
实现递归的getTypeProperties函数,通过Proxy的get陷阱递归创建子Proxy,并拼接父路径与当前属性名:
export function getTypeProperties<T>(parentPath = ''): PropertiesOf<T> { return new Proxy({}, { get: (_target, prop: string) => { // 拼接完整路径:如果有父路径则用点连接,否则直接用当前属性名 const fullPath = parentPath ? `${parentPath}.${prop}` : prop; // 延迟创建子Proxy,访问子属性时自动拼接路径 return getTypeProperties<any>(fullPath); } }) as PropertiesOf<T>; }
使用示例
1. 定义行类型
type myTableValuesRowType = { firstColumn: number; secondColumn: string; thirdColumn: number[]; fourthColumn: boolean; subrow: { firstSubrowColumn: string; secondSubrowColumn: number; nestedSubrow: { deepColumn: boolean; } } }
2. 在组件中生成属性路径对象
// component.ts readonly rowProperties = getTypeProperties<myTableValuesRowType>();
3. 在模板中使用
<my-table [values]="myTableValues"> <my-column [field]="rowProperties.firstColumn" /> <my-column [field]="rowProperties.subrow.firstSubrowColumn" /> <my-column [field]="rowProperties.subrow.nestedSubrow.deepColumn" /> </my-table>
4. 验证结果
console.log(rowProperties.firstColumn); // 输出 "firstColumn" console.log(rowProperties.subrow.firstSubrowColumn); // 输出 "subrow.firstSubrowColumn" console.log(rowProperties.subrow.nestedSubrow.deepColumn); // 输出 "subrow.nestedSubrow.deepColumn" console.log(rowProperties.thirdColumn); // 输出 "thirdColumn"
关键说明
- 类型安全:TypeScript会严格校验属性访问,不存在的属性会直接报类型错误,避免拼写错误。
- 递归拼接路径:通过传递父路径参数,每次访问子属性时自动拼接完整路径字符串。
- 数组处理:数组类型直接返回属性名本身,符合表格组件通常的字段路径规则(不需要索引,直接用数组属性名)。
- 无侵入:无需修改第三方UI组件库,完全通过类型工具和Proxy实现解耦。
内容的提问来源于stack exchange,提问作者T. Jami
相关产品推荐
相关产品推荐

