如何在类中使用约束标识函数实现物品系统?
物品系统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") });
关键调整说明
setCost方法泛型独立化:给setCost添加独立泛型U,调用setCost("money")时会直接返回Item<"money">,避免泛型被推导为宽泛的string。makeItems泛型约束优化:将参数约束为{ [key in K]: Item<K> },让TypeScript自动推断所有物品ID的联合类型,确保每个Item的cost只能引用已声明的物品ID。Item类默认泛型参数:给Item的泛型T设置默认值string,避免new Item()未指定泛型时直接报错,后续由makeItems约束为正确的联合类型。
修改后既保留了itemID的自动推断与补全能力,又解决了类型不匹配的错误。
内容的提问来源于stack exchange,提问作者SimplyNo
相关产品推荐
相关产品推荐

