I have a class with a protected map that contains some values, and a class method that adds new values to the map.
class Container {
protected readonly values: Map<PropertyKey, number> = new Map();
public addValue(key: PropertyKey, value: number): void {
if (this.values.has(key)) {
throw new Error('key already exists');
} else {
this.values.set(key, value);
}
}
}
Is it possible to type this class and function so that successive calls to the addValue function would produce a type error if the key already exists in the map? Having it throw an Error is easy enough, but I’m wondering if it is possible to perform this check with the Typescript compiler.
const container = new Container();
container.addValue('foo', 1); // valid
container.addValue('bar', 2); // valid
container.addValue('foo', 3); // invalid - foo already exists!
>Solution :
class Container<K extends PropertyKey = never> {
protected readonly values: Map<K, number> = new Map();
public addValue<P extends PropertyKey>(key: Exclude<P, K>, value: number) {
if (this.values.has(key as any as K)) {
throw new Error('key already exists');
} else {
this.values.set(key as any as K, value);
}
return this as Container<K | P>
}
}
let container = new Container()
.addValue('foo', 1) // valid
.addValue('bar', 2) // valid
.addValue('foo', 3) // invalid - foo already exists!