能否让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_
相关产品推荐
相关产品推荐

