You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归类型性能优化:解决嵌套状态路径类型编译过慢问题

优化嵌套对象状态路径的递归类型性能

我用对象存储应用的全部状态,由于对象嵌套层级不固定,需要定义状态路径类型来选取部分状态。目前写的递归类型满足以下需求:

  • 可描述从根节点到任意子属性的字符串数组路径
  • 支持在任意层级终止路径
  • 仅允许选取子节点,不能选兄弟或祖先节点
  • 数组属性支持通过索引或断言函数选取元素

但哪怕是简单的状态接口,这个递归类型编译速度都极慢。我已经限制了类型深度,超过阈值后回退为any,但面对业务里的复杂状态接口,性能还是不行。希望优化这个类型,优先实现无限制递归,也接受手动循环10层级后回退为any的方案。


方案一:手动展开10层级(性能最优)

将递归逻辑拆分为静态定义的10个层级,彻底避免递归类型的性能开销,同时保留所有需求特性:

// 断言函数类型定义
export type PredicateFunction<ArrayType> = (item: ArrayType, index?: number) => boolean;
export type IndexOrPredicate<Type> = number | PredicateFunction<Type>;

// 顶层路径类型:允许空路径或进入第一层
export type StatePath<Obj> = [] | StatePathLevel1<Obj>;

// 第1层处理逻辑
type StatePathLevel1<Obj> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            // 数组:允许索引/断言,或继续进入第二层
            [IndexOrPredicate<Obj[number]>] | StatePathLevel2<Obj[number], [IndexOrPredicate<Obj[number]>]>
            :
            // 对象:遍历所有合法键,允许选键后继续进入第二层
            { [K in keyof Obj & string]: [K] | StatePathLevel2<Obj[K], [K]> }[keyof Obj & string]
        )
        : [];

// 第2层处理逻辑
type StatePathLevel2<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel3<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel3<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第3层处理逻辑
type StatePathLevel3<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel4<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel4<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第4层处理逻辑
type StatePathLevel4<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel5<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel5<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第5层处理逻辑
type StatePathLevel5<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel6<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel6<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第6层处理逻辑
type StatePathLevel6<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel7<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel7<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第7层处理逻辑
type StatePathLevel7<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel8<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel8<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第8层处理逻辑
type StatePathLevel8<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel9<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel9<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第9层处理逻辑
type StatePathLevel9<Obj, Prev extends any[]> = 
    Obj extends object ?
        (Obj extends readonly any[] ?
            [...Prev, IndexOrPredicate<Obj[number]>] | StatePathLevel10<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            { [K in keyof Obj & string]: [...Prev, K] | StatePathLevel10<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : Prev;

// 第10层及以后:回退为宽松类型,平衡性能与兼容性
type StatePathLevel10<Obj, Prev extends any[]> = 
    Obj extends object ?
        [...Prev, ...(string | IndexOrPredicate<any>)[]]
        : Prev;

// 示例状态接口
export interface State {
    app: {
        testEntry: string;
        testArray: {
            firstname: string,
            lastname: string,
            address?: {
                zip: number;
                street: string;
                doorNumbers: {
                    number: number;
                    appendixes: number[];
                }[]
            }
        }[];
    }
}

// 合法路径示例
const path1: StatePath<State> = ['app', 'testEntry'];
const path2: StatePath<State> = ['app', 'testArray'];
const path3: StatePath<State> = ['app', 'testArray', 1, 'firstname'];
const path4: StatePath<State> = ['app', 'testArray', 5, 'address', 'doorNumbers', (doorNumber) => doorNumber.number === 1, 'appendixes'];

优化点说明

  • 用静态层级替换递归,彻底消除递归类型的重复推导开销,编译速度大幅提升
  • 每一层都保留“中途终止路径”的特性
  • 数组和对象的分支逻辑清晰,严格遵循需求规则
  • 10层后回退为宽松类型,避免过度类型推导影响性能

方案二:优化递归版本(接近无限制层级)

利用TypeScript 4.1+的条件类型延迟求值特性,让递归仅在需要具体推导时展开,而非一次性遍历所有可能路径:

// 断言函数类型定义
export type PredicateFunction<ArrayType> = (item: ArrayType, index?: number) => boolean;
export type IndexOrPredicate<Type> = number | PredicateFunction<Type>;

// 优化后的递归路径类型
type StatePathRecursive<Obj, Prev extends any[] = []> = 
    // 允许终止在当前层级
    Prev | 
    // 仅当Obj是对象时才继续推导,利用延迟求值避免立即展开所有层级
    (Obj extends object ?
        (Obj extends readonly any[] ?
            // 数组分支:推导下一层路径
            StatePathRecursive<Obj[number], [...Prev, IndexOrPredicate<Obj[number]>]>
            :
            // 对象分支:遍历所有合法键,推导下一层路径
            { [K in keyof Obj & string]: StatePathRecursive<Obj[K], [...Prev, K]> }[keyof Obj & string]
        )
        : never);

// 示例使用
const path: StatePathRecursive<State> = ['app', 'testArray', 0, 'address', 'doorNumbers', (d) => d.number === 1];

优化点说明

  • 利用条件类型延迟求值,只有当TypeScript需要校验具体路径时才会展开递归,初始编译开销极低
  • 理论上支持无限层级(受TypeScript默认递归深度限制,约1000层)
  • 完全保留所有需求特性,类型安全性不受影响

内容的提问来源于stack exchange,提问作者Stefan Holzapfel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 08:20:53