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

如何更新类实例属性的类型?Builder类store类型未同步问题

解决Builder类中store属性类型无法随addEntry调用同步更新的问题

问题核心在于你的BuilderUsingPlugins类仅用泛型跟踪了插件列表,没有跟踪store的动态结构。TypeScript中类实例的类型是静态绑定的,仅通过方法返回交叉类型无法改变原始实例的静态类型定义。

解决方案:用泛型参数跟踪store的结构

调整类的泛型定义,新增参数S表示当前store的类型,每次调用addEntry时返回更新了S泛型的新实例类型:

type plugin = {
  name: string,
  createEntry(...params: any[]): any
}
type PluginMap<T extends ReadonlyArray<plugin>> = {
  [key in T[number] as key["name"]]: key["createEntry"] extends ((...args: any[]) => any) ? key["createEntry"] : never
}

type UsingPluginMap<T extends ReadonlyArray<plugin>, Key extends T[number]["name"]> = PluginMap<T>[Key]

class BuilderUsingPlugins<T extends ReadonlyArray<plugin>, S extends Record<PropertyKey, any> = {}> {
  store: S = {} as S;
  plugins: PluginMap<T>;

  addEntry<P extends T[number]["name"], K extends PropertyKey>(
    pluginValueType: P,
    name: K,
    ...pluginParams: Parameters<UsingPluginMap<T, P>>
  ): BuilderUsingPlugins<T, S & Record<K, ReturnType<UsingPluginMap<T, P>>>> {
    const entryValue = this.plugins[pluginValueType](...pluginParams);
    this.store = { ...this.store, [name]: entryValue } as S & Record<K, ReturnType<UsingPluginMap<T, P>>>;
    
    return this as BuilderUsingPlugins<T, S & Record<K, ReturnType<UsingPluginMap<T, P>>>>;
  }

  constructor(params: T) {
    this.plugins = params.reduce((acc, curr) => {
      return {
        ...acc,
        ...{ [curr.name]: curr.createEntry } as const satisfies PluginMap<[typeof curr]>
      };
    }, {}) as PluginMap<typeof params>;
  }
}

// 插件定义保持不变
const fooPlugin={
  createEntry(){
    return 'I am the "foo" plugin!'
  },
  name:"foo"
} as const satisfies plugin

const barPlugin = {
  name:"bar",
  createEntry(someparam:number):number{
    return someparam
  }
} as const satisfies plugin

const bazPlugin = {
  name:"baz",
  createEntry(enumishArg:["hello","world"][number]):["hello","world"][number]{
    return enumishArg
  }
} as const satisfies plugin
const bastoPlugin = {
  name:"basto",
  createEntry(enump:ReadonlyArray<string>):typeof enump{
    return enump as typeof enump
  }
} as const satisfies plugin
const MyPluginList = [fooPlugin,barPlugin,bazPlugin,bastoPlugin] as const 

// 测试
const builder = new BuilderUsingPlugins<typeof MyPluginList>(MyPluginList);
// 接收返回值以获取更新后的类型
const updatedBuilder = builder.addEntry("foo", "fooEntry");
updatedBuilder.store.fooEntry; // 类型正确推断为string

// 链式调用时类型自动累积
const chainedBuilder = builder.addEntry("foo", "fooEntry")
  .addEntry("bar", "barEntry", 123)
  .addEntry("baz", "bazEntry", "hello");
chainedBuilder.store; // 类型为 { fooEntry: string; barEntry: number; bazEntry: "hello" | "world"; }

关键说明

  1. 泛型跟踪store结构:通过S泛型参数记录当前store的所有键值类型,每次调用addEntry时将新键值对类型与原S交叉,生成新的泛型类型。
  2. 突破静态类型限制:原代码中store的类型始终是初始的{},因为类的静态类型不会随实例方法调用动态改变。返回新的泛型实例类型后,TypeScript能正确跟踪store的结构变化。
  3. 简化类型断言:直接通过对象扩展更新store并断言类型,比原assignAndAssert更简洁,同时保证类型准确。

注意:TypeScript不会自动修改已有变量的静态类型,因此需要用新变量接收addEntry的返回值才能获取更新后的store类型。若必须复用原变量,可使用类型断言,但会降低类型安全性,不推荐。

内容的提问来源于stack exchange,提问作者A Kam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:15:57