TypeScript如何模拟类型层面的展开运算符实现类型复用
TypeScript类型系统模拟展开运算符实现类型复用
需求背景
需要在TypeScript类型系统中模拟JS展开运算符的行为,例如期望type tt = {...{t1:number},t2:number}等价于type tt = {t1:number,t2:number}。
具体实现目标:复用已有类型t(定义为t={t1:any; t2:any}),构造目标类型type tt = { t1:any; t2:any; specific:{t1:any; t2:any} },实现类似{ ...t; specific:t }的写法效果(实际场景中待复用的类型结构远比示例复杂)。
现有尝试的问题
- 递归自引用写法存在缺陷:
type tt = { t1:any; t2:any; specific:tt };语法可生效,但会产生非预期的无限嵌套结构:期望仅可正常访问tt.specific.t1,但该写法下tt.specific.specific甚至更深层的specific属性都会被TypeScript推断为合法,不符合需求。 - 映射类型直接追加属性无法编译:
type t = { t1: any; t2: any;} type tt = { [key in keyof t]: t[key], specific: tt }; // ^ 映射类型语法中不允许直接追加额外属性
注:Typescript spread operator for type相关讨论不是本问题的重复问题。
实现方案
通过映射类型+交叉类型的组合即可模拟展开运算符的行为,既可以完整复用原有类型的所有属性(包括可选、只读等修饰符),也可以追加自定义属性,同时避免无限递归问题:
type t = { t1: any; t2: any; } // 直接实现:先通过映射类型遍历取出t的所有属性,再交叉追加specific属性 type tt = { [K in keyof t]: t[K] } & { specific: t };
如果需要在多处复用这种展开逻辑,可以封装为通用工具类型:
// 通用类型展开工具,等价于类型层面的{...T, ...U} type Spread<T, U> = { [K in keyof T]: T[K] } & U; // 使用方式 type tt = Spread<t, { specific: t }>;
效果验证
- 可正常访问
tt.t1、tt.t2,类型与t中定义完全一致 - 可正常访问
tt.specific.t1、tt.specific.t2 - 访问
tt.specific.specific会直接抛出类型错误,不存在无限嵌套问题,完全符合预期。
内容的提问来源于stack exchange,提问作者Eliav Louski
相关产品推荐
相关产品推荐

