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

TypeScript:使用泛型与链式调用实现类字段动态类型

问题分析与解决方案

你的核心需求是让Service类的models字段类型能随着use()调用动态合并插件的模型类型,但当前代码存在几个关键问题:

  1. 泛型参数设计错误:use方法的NewService泛型绑定的是Service<any>,但传入的参数是ModelList实例而非Service实例,导致类型推断完全偏离预期。
  2. 返回类型不匹配:条件类型的逻辑无法正确映射到实际返回的this类型,TypeScript无法自动将Service<Models>推断为合并后的Service<NewModels & Models>。
  3. 模型类型无法精确提取:原ModelList接口的models()返回宽泛的Record<string, string>,无法获取插件的具体模型结构。

修正后的代码

export type MaybePromise<T> = T | Promise<T>;

type ModelBase = Record<string, string>;

// 改为泛型接口,让ModelList携带自身的模型类型
export interface ModelList<M extends ModelBase> {
  models(): MaybePromise<M>;
}

class ModelListImpl implements ModelList<{ model_1: string; model_2: string }> {
  models() {
    return {
      model_1: 'model-1',
      model_2: 'model-2',
    };
  }
}

class Service<Models extends ModelBase = Record<string, never>> {
  models: Models = {} as Models;

  // 同步版本:接收ModelList<M>,返回合并类型后的Service
  use<M extends ModelBase>(service: ModelList<M>): Service<Models & M>;
  // 异步版本:处理models()返回Promise的情况
  use<M extends ModelBase>(service: ModelList<M>): Promise<Service<Models & M>>;
  // 实现逻辑
  async use<M extends ModelBase>(service: ModelList<M>) {
    const models = await service.models();
    this.models = { ...this.models, ...models } as Models & M;
    // 断言返回类型为合并后的Service
    return this as unknown as Service<Models & M>;
  }
}

// 同步调用示例
(async () => {
  let service = new Service();
  service = service.use(new ModelListImpl());
  // 此时service.models类型为{ model_1: string; model_2: string }
  console.log(service.models.model_1); // 类型提示正常
})();

// 异步插件示例
class AsyncModelList implements ModelList<{ model_3: string }> {
  async models() {
    return { model_3: 'model-3' };
  }
}

(async () => {
  let service = new Service();
  service = await service.use(new AsyncModelList());
  // 此时service.models类型为{ model_3: string }
  console.log(service.models.model_3);
})();

关键修改点说明

  • 泛型ModelList:让ModelList接口携带具体的模型类型M,调用use()时能精确提取插件的模型结构,替代模糊的Record<string, string>。
  • 方法重载:针对models()返回同步值和Promise的情况做重载,确保返回类型正确(同步返回Service<Models & M>,异步返回Promise<Service<Models & M>>)。
  • 类型断言:由于TypeScript无法自动识别this的泛型类型变化,通过as unknown as Service<Models & M>手动断言返回类型,保证类型提示生效。
  • 异步统一处理:使用await覆盖同步和异步的models()返回值,避免冗余分支逻辑。

修改后,每次调用use(),service.models的类型都会自动合并新插件的模型字段,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:41:23