'Map Typescript generic array
Suppose I have an object with a static set of keys, and then a type specifying a subset of those keys as a static array:
const myBigStaticObject = {
key1: () => 'foo',
key2: () => 'bar',
// ...
keyN: () => 'fooN',
}
type BigObject = typeof myBigStaticObject
type Keys = ['key2', 'keyN']
Is there a nice way of then programmatically creating a mapped type which takes Keys
as its generic argument, i.e. does the following:
type ObjectValueFromKeys<K extends (keyof BigObject)[]> = // ???
// such that:
ObjectValueFromKeys<Keys> = [() => 'bar', () => 'fooN']
The equivalent for objects here would be:
const objectKeys = {
a1: 'key2';
a2: 'keyN';
}
type ObjectValueFromObjectKeys<M extends Record<string, keyof BigObject>> = {
[K in keyof M]: BigObject[M[K]]
}
// then
type ObjectValueFromObjectKeys<typeof objectKeys> = {
a1: () => 'bar';
a2: () => 'fooN';
}
Solution 1:[1]
You may not know this but you can actually use a mapped type with arrays and tuples while still retaining the array/tuple type in the output!
That means you can use something like this, where it checks if the value is a key of the big object first:
type ObjectValueFromKeys<K extends (keyof BigObject)[]> = {
[P in keyof K]: K[P] extends keyof BigObject ? BigObject[K[P]] : K[P];
};
And it works like a charm:
type T1 = ObjectValueFromKeys<["key2", "keyN"]>;
// ^? [() => "bar", () => "fooN"]
Don't believe me? See for yourself.
You will probably notice that there is as const
used in the big object:
key1: () => 'foo' as const,
This is because, for some reason, TypeScript can't deduce that this function can only return "foo"
. And so I have used as const
to make it return the literal "foo"
for our case so we can see if the solution works.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |