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

如何在类中使用约束标识函数实现物品系统?

物品系统TypeScript类型推断问题解决

问题背景

需要实现一个物品系统,通过makeItems函数声明物品,每个物品的cost属性需能引用注册表中的其他物品ID。

原本使用对象结合泛型约束的代码可正常运行:

const makeItems = <K extends PropertyKey, C extends K>(items: Record<K, {cost?: C}>) => items
const items = makeItems({
  money: {},
  dirt: {
    cost: "money", // TypeScript会自动补全为"dirt" | "money"
  },
})

现在要将实现改为类,定义基础物品类如下:

class Item<T extends string> {
  public cost?: T;
  constructor() {}
  public setCost(item: T) {
    this.cost = item;
    return this;
  }
}

更新后的声明代码:

const makeItems = <T extends string, C extends T>(items: Record<T, Item<C>>) => items;
const items = makeItems({
  money: new Item(),
  dirt: new Item().setCost("money")
})

但改成类后出现类型错误:

Type 'Item' is not assignable to type 'Item<"money" | "dirt">'.
Type 'string' is not assignable to type '"money" | "dirt"'.

需要在保留TypeScript对itemID自动推断能力的前提下解决该错误。

解决方案

问题根源在于Item类的泛型推导与makeItems的泛型约束不匹配,调整泛型定义即可解决:

修改后的代码

class Item<T extends string = string> {
  public cost?: T;
  constructor() {}
  public setCost<U extends string>(item: U): Item<U> {
    this.cost = item as T & U;
    return this as unknown as Item<U>;
  }
}

const makeItems = <K extends PropertyKey>(items: { [key in K]: Item<K> }) => items;

const items = makeItems({
  money: new Item(),
  dirt: new Item().setCost("money")
});

关键调整说明

  1. setCost方法泛型独立化:给setCost添加独立泛型U,调用setCost("money")时会直接返回Item<"money">,避免泛型被推导为宽泛的string。
  2. makeItems泛型约束优化:将参数约束为{ [key in K]: Item<K> },让TypeScript自动推断所有物品ID的联合类型,确保每个Item的cost只能引用已声明的物品ID。
  3. Item类默认泛型参数:给Item的泛型T设置默认值string,避免new Item()未指定泛型时直接报错,后续由makeItems约束为正确的联合类型。

修改后既保留了itemID的自动推断与补全能力,又解决了类型不匹配的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:13:15