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

TypeScript多泛型方法模式:类方法自由组合实现方案问询

TypeScript 泛型实现Person方法的自由组合

要实现不用子类、仅通过泛型参数指定方法实现的组合需求,可以通过标记类型映射+泛型类的方式优雅解决,编译时即可确定类型,实例化时无需传递函数参数,具体实现如下:

1. 定义实现标记与映射关系

先为每个方法的不同实现定义唯一的类型标记,再创建标记到具体实现的映射:

// 定义getFirstName的实现类型标记
type FirstNameTag = "Alice" | "Bob";
// 定义getSurname的实现类型标记
type SurnameTag = "Smith" | "Jones";

// 方法实现的类型约束
type FirstNameProvider = { getFirstName: () => string };
type SurnameProvider = { getSurname: () => string };

// 标记到具体实现的映射
const FirstNameMap: Record<FirstNameTag, FirstNameProvider> = {
  Alice: { getFirstName: () => "Alice" },
  Bob: { getFirstName: () => "Bob" },
};

const SurnameMap: Record<SurnameTag, SurnameProvider> = {
  Smith: { getSurname: () => "Smith" },
  Jones: { getSurname: () => "Jones" },
};

2. 泛型Person类实现

创建泛型类,通过泛型参数接收实现标记,直接从映射中获取对应方法实现并绑定到类:

class Person<F extends FirstNameTag, S extends SurnameTag> implements FirstNameProvider, SurnameProvider {
  // 直接从映射中获取对应实现,编译时会检查标记的合法性
  getFirstName = FirstNameMap[F].getFirstName;
  getSurname = SurnameMap[S].getSurname;
}

3. 实例化与使用

实例化时仅需指定泛型参数,无需传递任何函数参数,所有组合都可自由生成:

// 生成Alice Smith的实例
const aliceSmith = new Person<"Alice", "Smith">();
console.log(aliceSmith.getFirstName()); // 输出: Alice
console.log(aliceSmith.getSurname());  // 输出: Smith

// 生成Bob Jones的实例
const bobJones = new Person<"Bob", "Jones">();
console.log(bobJones.getFirstName()); // 输出: Bob
console.log(bobJones.getSurname());  // 输出: Jones

扩展:支持有状态的方法实现

如果方法需要依赖实例状态,可调整类的实现,确保方法绑定到实例上下文:

// 带状态的FirstName实现
type StatefulFirstNameProvider = FirstNameProvider & { prefix: string };

const StatefulFirstNameMap: Record<FirstNameTag, StatefulFirstNameProvider> = {
  Alice: {
    prefix: "Ms.",
    getFirstName() {
      return `${this.prefix} Alice`;
    },
  },
  Bob: {
    prefix: "Mr.",
    getFirstName() {
      return `${this.prefix} Bob`;
    },
  },
};

class StatefulPerson<F extends FirstNameTag, S extends SurnameTag> implements FirstNameProvider, SurnameProvider {
  private firstNameImpl: StatefulFirstNameProvider;
  private surnameImpl: SurnameProvider;

  constructor() {
    // 克隆实现对象,避免实例间状态污染
    this.firstNameImpl = { ...StatefulFirstNameMap[F] };
    this.surnameImpl = { ...SurnameMap[S] };
    // 绑定方法到当前实例
    this.getFirstName = this.getFirstName.bind(this);
  }

  getFirstName(): string {
    return this.firstNameImpl.getFirstName.call(this);
  }

  getSurname(): string {
    return this.surnameImpl.getSurname();
  }

  // 允许修改实例状态
  setPrefix(prefix: string) {
    this.firstNameImpl.prefix = prefix;
  }
}

// 使用示例
const alice = new StatefulPerson<"Alice", "Smith">();
console.log(alice.getFirstName()); // 输出: Ms. Alice
alice.setPrefix("Dr.");
console.log(alice.getFirstName()); // 输出: Dr. Alice

该方案的优势:

  • 避免了为每种组合创建子类,新增实现仅需添加标记和对应映射项
  • 泛型参数在编译时会进行类型校验,确保指定的实现标记合法
  • 实例化过程简洁,仅需指定泛型参数,无需传递额外参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:47:06