Last active
September 22, 2022 07:35
-
-
Save artalar/a2157bba77f95d90de7e4115a7abc60e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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