TypeScript嵌套字段类型推断性能优化问询
问题分析
原方案通过NestedKeyOf和NestedValueOf递归生成所有可能的嵌套字段路径联合类型,当模型层级达到3层以上且包含20-30个属性时,联合类型的规模会指数级膨胀。TypeScript类型检查器需要处理大量的类型组合,导致计算耗时剧增。
优化方案
1. 限制嵌套层级,减少递归计算
通过限制支持的嵌套层数(比如最多2-3层),避免无限递归生成所有可能路径,大幅降低类型计算量:
// 仅支持最多2层嵌套的字段路径类型 type NestedKeyOf2<T> = keyof T | { [K in keyof T & string]: T[K] extends object ? `${K}.${keyof T[K] & string}` : never }[keyof T & string]; // 对应2层嵌套的字段值类型 type NestedValueOf2<T, K extends string> = K extends keyof T ? T[K] : K extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? Tail extends keyof T[Head] ? T[Head][Tail] : never : never : never; // 优化后的Column接口 interface Column<T, K extends NestedKeyOf2<T>> { field: K; transformation?: (value: NestedValueOf2<T, K>, data: T) => string; }
如果需要支持3层嵌套,可手动扩展类型定义,避免无限制递归带来的性能损耗。
2. 简化递归逻辑,合并冗余类型分支
原方案中多个辅助类型(如IsArray、IsComplexObject)增加了类型解析的复杂度,合并这些分支可提升TypeScript的计算效率:
// 简化的嵌套字段路径类型,跳过Date/Blob等不可遍历类型 type NestedKeyOf<T> = T extends Date | Blob | string | number ? never : T extends Array<infer U> ? `${number}` | `${number}.${NestedKeyOf<U>}` : keyof T | { [K in keyof T & string]: `${K}.${NestedKeyOf<T[K]>}` }[keyof T & string]; // 简化的嵌套字段值类型 type NestedValueOf<T, K extends string> = K extends keyof T ? T[K] : K extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? Head extends `${number}` ? T extends Array<infer U> ? NestedValueOf<U, Tail> : never : NestedValueOf<T[Head], Tail> : never : never;
3. 延迟类型推断,逐个解析字段
通过创建辅助函数,让TypeScript在定义每个Column时才推断对应字段的类型,而非一次性计算所有可能的路径联合:
function createColumn<T>(column: { field: NestedKeyOf<T>; transformation?: (value: NestedValueOf<T, typeof column.field>, data: T) => string; }) { return column; } // 使用示例 const columns = [ createColumn<Model>({ field: 'field1', transformation: (value) => value.getTime().toString() }), createColumn<Model>({ field: 'nested.subField', // 假设Model包含nested: { subField: string } transformation: (value) => value.toUpperCase() }) ];
这种方式下,TypeScript仅针对每个createColumn调用计算对应的字段类型,避免了大规模联合类型的预计算。
替代方案:手动指定类型(性能最优)
对于超复杂模型,完全放弃自动嵌套推断,手动指定每个Column的字段类型,获得最高性能:
interface Column<T, K extends string, V> { field: K; transformation?: (value: V, data: T) => string; } // 使用示例 const columns: Column<Model, 'field1', Date>[] = [ { field: 'field1', transformation: (value) => value.getTime().toString() } ];
内容的提问来源于stack exchange,提问作者user28851393
相关产品推荐
相关产品推荐

