Skip to content

Instantly share code, notes, and snippets.

@artalar
Last active September 22, 2022 07:35
Show Gist options
  • Save artalar/a2157bba77f95d90de7e4115a7abc60e to your computer and use it in GitHub Desktop.
Save artalar/a2157bba77f95d90de7e4115a7abc60e to your computer and use it in GitHub Desktop.
type M = [any, any];
type Delete<k, m extends M> = k extends m[0]
? m extends [k, any]
? never
: m
: m[0] extends k
? [unknown, unknown]
: m;
type Add<k, v, m extends M> = [k, v] | Delete<k, m>;
type Get<k, m extends M> = k extends m[0]
? m extends [k, infer v]
? v
: never
: m[0] extends k
? unknown
: never;
type Keys<m extends M> = m extends [infer k, any] ? k : never;
type Values<m extends M> = m extends [any, infer v] ? v : never;
class TypedMap<T extends [keyof any, any]> {
private _map: object;
constructor(map: { [k: T[0]]: T[1] } = {}) {
this._map = map;
}
get keys(): T[0] {
return Object.keys(this._map) as any;
}
get values(): T[1] {
return Object.values(this._map) as any;
}
delete<k extends keyof any>(k: k): TypedMap<Delete<k, T>> {
const { [k]: deleted, ...newMap } = this._map;
return new TypedMap(newMap) as any;
}
add<k extends keyof any, v extends number>(
k: k,
v: v
): TypedMap<Add<k, v, T>> {
return new TypedMap({ ...this._map, [k]: v });
}
get<k extends T[0]>(k: k): Get<k, T>;
get<k>(k: k): /* T[0] extends k ? unknown : */never;
get(k) {
return this._map[k];
}
}
const m0 = new TypedMap<[0, 0]>({ 0: 0 });
const m1 = m0.add(1, 10);
const m2 = m1.add(2, 20);
const m3 = m2.add(3, 30);
const test_30 = m3.get(3);
const test_never1 = m3.get('-1');
const test_never2 = m3.delete(3).get('3');
const test_20 = m3.delete(3).get(2);
const test_unknown1 = m3.get(-1 as number);
const test_same1 = m3.delete(-1);
const test_same2 = m3.add(3, 30);
const test_300 = m3.add(3, 300).get(3);
const test_never3 = m3.add(3, 300).delete(3).get(3);
const test_unknown2 = m3.delete(-1 as number);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment