TypeScript中能否静态存储泛型累积可变类型?
如何在TypeScript中静态累积
create调用的类型(不依赖this类型变更与代码生成) 问题背景
用户希望在TypeScript中实现静态存储类型,当前示例通过Screen类的create方法,利用this: Screen<[Output, D]>强制修改实例泛型类型来累积每次调用的ScreenDefinition类型。但需求是不借助代码生成、不使用Screen<[Output, D]>作为this参数类型的前提下,实现同样的类型存储效果。
原示例代码:
type ScreenDefinition<Name extends string, Path extends string> = { name: Name; path: Path; }; class Screen<Output = any> { _output!: Output; create< Name extends string, Path extends string, D extends ScreenDefinition<Name, Path> >(this: Screen<[Output, D]>, def: D) { this._output = [...this._output, def] as unknown as [Output, D]; return this._output as unknown as [Output, D]; } } const AdminRootScreen = new Screen(); AdminRootScreen.create({ name: "My screen", path: "/my-screen", routePath: ["/my-screen"], accessPath: "test", }); type Routes<RS> = RS extends Screen<any> ? RS["_output"] : never; type AdminRoutes = Routes<typeof AdminRootScreen>; // 期望获取累积的ScreenDefinition类型
解决方案
可以通过让create方法返回新的Screen实例,并将当前泛型类型与新的ScreenDefinition合并,实现类型的静态累积,完全无需修改this的类型约束。
修改后的代码:
type ScreenDefinition<Name extends string, Path extends string> = { name: Name; path: Path; }; // 辅助类型:处理初始空数组与后续类型追加逻辑 type AppendScreenOutput<CurrentOutput, NewDef> = CurrentOutput extends any[] ? [...CurrentOutput, NewDef] : [NewDef]; class Screen<Output extends any[] = []> { _output!: Output; create<Name extends string, Path extends string, D extends ScreenDefinition<Name, Path>>(def: D) { // 运行时合并数据 this._output = [...(this._output ?? []), def] as Output; // 返回带更新后泛型的新实例,实现类型累积 return new Screen<AppendScreenOutput<Output, D>>() as unknown as Screen<AppendScreenOutput<Output, D>>; } } // 初始实例,泛型默认是空数组 const AdminRootScreen = new Screen(); // 每次create返回新实例,类型自动追踪累积 const updatedScreen = AdminRootScreen.create({ name: "My screen", path: "/my-screen", routePath: ["/my-screen"], accessPath: "test", }); // 再次调用create,类型继续追加 const finalScreen = updatedScreen.create({ name: "Settings", path: "/settings", }); // 提取累积的类型 type Routes<RS> = RS extends Screen<infer O> ? O : never; type AdminRoutes = Routes<typeof finalScreen>; // 最终类型为: // [ // { name: "My screen"; path: "/my-screen"; routePath: string[]; accessPath: string; }, // { name: "Settings"; path: "/settings"; } // ]
原理说明
- 泛型累积机制:将
Screen类的泛型Output限定为数组类型,初始默认是空数组[]。每次调用create时,通过AppendScreenOutput辅助类型将新的ScreenDefinition追加到当前的Output数组类型中。 - 返回新实例:
create方法不再修改当前实例的类型,而是返回带有新泛型参数的Screen实例,让TypeScript静态追踪每次调用后的类型变化。 - 运行时兼容:运行时正常合并
_output数组,类型断言仅用于让TypeScript接受赋值操作,不影响实际功能。
这种方式完全依赖TypeScript泛型特性实现类型静态累积,既不需要修改this类型,也无需代码生成。
内容的提问来源于stack exchange,提问作者Kacper Ochmański
相关产品推荐
相关产品推荐

