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

能否让TypeScript在Map已有键时对addValue调用触发类型错误?

实现编译时检查重复键的Container类

要实现你需要的编译时重复键检查,核心是用TypeScript泛型跟踪已添加的键集合,让addValue方法返回一个更新了泛型约束的新实例,后续调用就能通过类型系统识别重复键。

修改后的代码实现

class Container<Keys extends PropertyKey = never> {
  protected readonly values: Map<PropertyKey, number> = new Map();

  public addValue<K extends Exclude<PropertyKey, Keys>>(
    key: K,
    value: number
  ): Container<Keys | K> {
    if (this.values.has(key)) {
      throw new Error('key already exists');
    }
    this.values.set(key, value);
    // 通过类型断言更新实例的泛型类型
    return this as Container<Keys | K>;
  }
}

用法验证

链式调用/赋值新变量的场景

const container = new Container();
const containerWithFoo = container.addValue('foo', 1); // 合法,返回Container<'foo'>
const containerWithFooBar = containerWithFoo.addValue('bar', 2); // 合法,返回Container<'foo' | 'bar'>

// 编译错误:类型'"foo"'不能赋值给类型'Exclude<PropertyKey, "foo" | "bar">'
containerWithFooBar.addValue('foo', 3); 

同一变量连续调用的场景

如果要在同一个变量上触发类型检查,需要将每次调用的返回值重新赋值给变量:

let container = new Container();
container = container.addValue('foo', 1);
container = container.addValue('bar', 2);
// 编译错误:'"foo"'不在允许的键范围内
container = container.addValue('foo', 3);

关键细节说明

  • 泛型参数Keys:用于记录当前实例已存在的键类型,默认值never表示初始状态无任何键。
  • Exclude<PropertyKey, Keys>:约束传入的key必须是Keys中未出现过的类型,重复时直接触发编译错误。
  • 返回更新后的泛型实例:addValue返回Container<Keys | K>,让后续调用能继承已有的键约束,实现类型的链式跟踪。
  • 保留运行时检查:即使绕过类型检查(比如传入动态生成的键),运行时的错误抛出逻辑依然能保障数据正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:22:41