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

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"; }
// ]

原理说明

  1. 泛型累积机制:将Screen类的泛型Output限定为数组类型,初始默认是空数组[]。每次调用create时,通过AppendScreenOutput辅助类型将新的ScreenDefinition追加到当前的Output数组类型中。
  2. 返回新实例:create方法不再修改当前实例的类型,而是返回带有新泛型参数的Screen实例,让TypeScript静态追踪每次调用后的类型变化。
  3. 运行时兼容:运行时正常合并_output数组,类型断言仅用于让TypeScript接受赋值操作,不影响实际功能。

这种方式完全依赖TypeScript泛型特性实现类型静态累积,既不需要修改this类型,也无需代码生成。

内容的提问来源于stack exchange,提问作者Kacper Ochmański

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:27:53