With function which returns values from object with some list of keys from the object like below.
function mapObjToArray(obj, keys) {
return keys.map(key => obj[key])
}
const result = mapObjToArray({ A: "a", B: "b", C: 'c', X: 'x'}, ['A', 'B'])
I want get exact type of result value, I mean ["a", "b"]
in this case, but, with code below, type of result is ("a" | "b" | "c" | "x")[]
instead of ["a", "b"]
.
function mapObjToArray<T>(obj: T, keys: (keyof T)[]) {
return keys.map(key => obj[key])
}
const result = mapObjToArray({ A: "a", B: "b", C: 'c', X: 'x'} as const, ['A', 'B'])
I may advanced little with Variadic Tuple Type and I got...
function mapObjToArrayWithVariadicTuple<T, X extends [...(keyof T)[]]>(obj: T, keys: X): [...T[X[number]][]] {
return keys.map(key => obj[key])
}
const resultVariadicTuple = mapObjToArrayWithVariadicTuple({ A: "a", B: "b", C: 'c', X: 'x'} as const, ['A', 'B'])
Getting closer, but still, typeof resultVariadicTuple is not I wanted ("a" | "b")[]
Is there any way to get the result type I want???
One sure thing is that both obj
and keys
parameters must be const
.
Otherwise, as types in TypeScript are detached from the runtime, the returned type is undeterminable.
If this requirement can be assumed, then something like this should be the answer:
type _Map<
K extends readonly any[],
O extends { [key in K[number]]: any }
> = K extends readonly []
? []
: K extends readonly [infer H, ...infer T]
? [O[H], ..._Map<T, O>]
: never;
function mapObjToArray<
K extends readonly (string | number | symbol)[],
O extends { [key in K[number]]: any }
>(obj: O, keys: K): _Map<K, O> {
return keys.map((key: K[number]) => obj[key]) as any;
}
const result = mapObjToArray(
{ A: "a", B: "b", C: "c", X: "x" } as const,
["A", "B"] as const
);