解决递归嵌套TS类型导致IntelliSense类型推断过慢问题
解决schema-org递归类型导致的IntelliSense性能问题
你的问题核心是递归类型在处理schema-org这种多层嵌套的复杂类型时,TypeScript类型检查器会反复遍历所有嵌套分支,导致计算量指数级上升,直接拖垮IntelliSense。下面给几个实用的优化方案:
1. 给递归添加深度限制
给递归类型加一个可选的深度参数,默认设置为5(足够覆盖schema-org绝大多数嵌套场景),当达到最大深度时直接终止递归,避免无限制遍历深层嵌套结构。
type PrimitiveValue = undefined | null | boolean | number | string; type Flattened<A> = A extends (infer E)[] ? Flattened<E> : A; type IdReference = {'@id': string;}; type PreprocessedSchemaOrgValue<TValue> = Exclude<TValue, IdReference | schemaOrg.Role>; // 新增深度限制参数,默认5层,可手动调整 type NormalizedSchemaOrgValue<T, Depth extends number = 5> = Depth extends 0 ? PreprocessedSchemaOrgValue<T> : // 深度触顶,直接返回预处理类型 T extends schemaOrg.Role ? never : T extends schemaOrg.Boolean ? boolean : T extends `${number}` ? number : T extends ((infer E)[] | readonly (infer E)[]) ? Flattened<NormalizedSchemaOrgValue<E, Depth>>[] : T extends {'@type': string | string[]} ? { [k in keyof T]: k extends '@id' | '@type' ? T[k] : T[k] extends PrimitiveValue ? Exclude<T[k], undefined>[] | undefined : Exclude<NormalizedSchemaOrgValue<T[k], [Depth] extends [1] ? 0 : Depth extends `${infer N extends number}` ? N-1 : never>, undefined>[] | undefined } : T extends IdReference ? never : PreprocessedSchemaOrgValue<T>;
如果需要支持更深的嵌套,手动传入深度参数即可,比如:NormalizedSchemaOrgValue<schemaOrg.Restaurant, 8>。
2. 合并基础类型判断,减少分支计算
把schema-org基础类型的转换逻辑提前做成映射表,减少每次递归的条件判断次数,降低类型检查器的计算开销:
type PrimitiveValue = undefined | null | boolean | number | string; type Flattened<A> = A extends (infer E)[] ? Flattened<E> : A; type IdReference = {'@id': string;}; type PreprocessedSchemaOrgValue<TValue> = Exclude<TValue, IdReference | schemaOrg.Role>; // 提前定义基础类型映射表 type SchemaOrgPrimitiveMap = { [K in schemaOrg.Boolean]: boolean; [K in `${number}`]: number; }; type NormalizedPrimitive<T> = T extends keyof SchemaOrgPrimitiveMap ? SchemaOrgPrimitiveMap[T] : T; type NormalizedSchemaOrgValue<T, Depth extends number = 5> = Depth extends 0 ? PreprocessedSchemaOrgValue<T> : T extends schemaOrg.Role | IdReference ? never : T extends ((infer E)[] | readonly (infer E)[]) ? Flattened<NormalizedSchemaOrgValue<E, Depth>>[] : T extends {'@type': string | string[]} ? { [k in keyof T]: k extends '@id' | '@type' ? T[k] : T[k] extends PrimitiveValue ? Exclude<NormalizedPrimitive<T[k]>, undefined>[] | undefined : Exclude<NormalizedSchemaOrgValue<T[k], [Depth] extends [1] ? 0 : Depth extends `${infer N extends number}` ? N-1 : never>, undefined>[] | undefined } : NormalizedPrimitive<PreprocessedSchemaOrgValue<T>>;
3. 关闭不必要的分布式条件判断
原来的T extends any ? ... : never是为了让联合类型的每个成员单独处理,但schema-org的类型包含大量联合分支,分布式遍历会让计算量暴增。直接去掉这个包裹,改为对整个类型进行条件判断:
type PrimitiveValue = undefined | null | boolean | number | string; type Flattened<A> = A extends (infer E)[] ? Flattened<E> : A; type IdReference = {'@id': string;}; type PreprocessedSchemaOrgValue<TValue> = Exclude<TValue, IdReference | schemaOrg.Role>; type SchemaOrgPrimitiveMap = { [K in schemaOrg.Boolean]: boolean; [K in `${number}`]: number; }; type NormalizedPrimitive<T> = T extends keyof SchemaOrgPrimitiveMap ? SchemaOrgPrimitiveMap[T] : T; type NormalizedSchemaOrgValue<T, Depth extends number = 5> = Depth extends 0 ? PreprocessedSchemaOrgValue<T> : // 直接处理整个类型,避免分布式遍历所有联合成员 T extends schemaOrg.Role | IdReference ? never : T extends ((infer E)[] | readonly (infer E)[]) ? Flattened<NormalizedSchemaOrgValue<E, Depth>>[] : T extends {'@type': string | string[]} ? { [k in keyof T]: k extends '@id' | '@type' ? T[k] : T[k] extends PrimitiveValue ? Exclude<NormalizedPrimitive<T[k]>, undefined>[] | undefined : Exclude<NormalizedSchemaOrgValue<T[k], [Depth] extends [1] ? 0 : Depth extends `${infer N extends number}` ? N-1 : never>, undefined>[] | undefined } : NormalizedPrimitive<PreprocessedSchemaOrgValue<T>>;
额外优化建议
- 如果某些嵌套类型不需要规范化,可以直接返回原始类型,进一步减少递归触发;
- 尽量使用
type而非interface定义中间类型,TypeScript对type的检查开销更低; - 可以尝试开启TypeScript的
--noStrictGenericChecks编译选项,降低泛型类型的检查复杂度(注意权衡类型安全性)。
内容的提问来源于stack exchange,提问作者Remirror
相关产品推荐
相关产品推荐

