'Typescript: return interface with keys based on array input
Here's what I'm trying to do:
Based on a string array I'd like to specify the return type as a record keyed by the strings.
e.g.
// return type -> { itemA:SomeType,itemB:SomeType }
const res = doThing(['itemA', 'itemB'])
Is this possible?
Solution 1:[1]
Yes, you need to make doThing() generic in the string entry types of the array you pass in. It could look like this:
function doThing<K extends string>(arr: readonly K[]): { [P in K]: string } {
return Object.fromEntries(arr.map(v => [v, "hello"])) as any;
}
Note that K extends string constrains K to be some subtype of string, and this gives the compiler a hint that you'd like it to infer string literal types for K as opposed to (the fairly useless) string. Note that the type of arr is readonly K[], a shorthand for the ReadonlyArray<K> type which, despite the name, corresponds to any array type, even those you can write to (whereas the Array<T> type corresponds to only those array types that are known to be writable. Yes, maybe it would be better to have named them differently, like PossiblyNotWritableArray<T> instead of Readonly<T>? ????). So readonly K[] is actually more permissive than K[].
The return type, {[P in K]: string} is a mapped type which iterates over the keys P in K and produces a string-valued property for each. This is equivalent to Record<K, string> using the Record<K, V> utility type.
Let's make sure it does what you want:
const res = doThing(['itemA', 'itemB']);
/*const res: {
itemA: string;
itemB: string;
}*/
console.log(res);
/* {
"itemA": "hello",
"itemB": "hello"
} */
Looks good!
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 | jcalz |
