Non-string keys in object literal syntax JS
At one point I was thinking on how one could use object literal syntax ({foo: 1, baz: true}
) to create Map tho use keys which are non-string values, number, object etc and wrote this code which kinda works. tho probably no one’s gonna use it including me :D
type KeyStore<T> = {
asKey: (value: T) => symbol;
fromKey: (key: symbol) => [] | [T];
};
const mkKeyStore = <T>(): KeyStore<T> => {
const map = new Map<symbol, T>();
const asKey = (value: T): symbol => {
const key = Symbol();
map.set(key, value);
return key;
};
const fromKey = (key: symbol): [] | [T] => {
if (map.has(key)) {
return [map.get(key)!];
}
return [];
};
return { asKey, fromKey };
};
const mapMakerMaker =
<K>(s: KeyStore<K>) =>
<T>(
record: Record<Extract<K, string | number | symbol> | symbol, T>
): Map<K, T> => {
const stringEntires: [string, T][] = Object.entries<T>(record);
const entires1 = stringEntires as any as [K, T][];
const symbols = Object.getOwnPropertySymbols(record);
const entries2 = symbols.flatMap((key) =>
s.fromKey(key).map((v): [K, T] => [v, record[key]])
);
const map = new Map<K, T>([...entires1, ...entries2]);
return map;
};
const keyStore = mkKeyStore<string | ["required", string]>();
const required = (key: string) => keyStore.asKey(["required", key]);
const mkMap = mapMakerMaker(keyStore);
const x = mkMap({
[required("name")]: "string",
age: "int",
});
console.log(x);
// Map (2) {"basd" => "int", ["required", "asd"] => "string"}