Reputation: 706
I have a method that takes as an input an object whose values are arrays of strings; it returns an object whose values are objects with keys equal to the string values. E.g.
myFunction({foo: ['a', 'b']}) // ==> {foo: {a: Widget, b: Widget}}
I'm trying to define the signature of this function. My best attempt is:
declare function myFunction
<Q extends string[], T extends {[key: string]: Q}>
(keys: T) : {[key1 in keyof T]: {[key2 in T[key1][number]]: Widget}}
This almost works, except the key names of the nested objects are not inferred. The first example returns:
{
foo: {
[x: string]: Widget;
};
}
whereas I want it to return
{
foo: {
a: Widget;
b: Widget;
};
}
Can that be done?
Upvotes: 0
Views: 571
Reputation: 20132
In order to allow TS to fix the inference we need to add additionaly generic type for array keys members:
declare function myFunction
<Q extends K[], T extends {[key: string]: Q}, K extends string>
(keys: T): { [key1 in keyof T]: { [key2 in T[key1][number]]: Widget } }
Pay attention at Q extends K[]
, we now are saying that Q
is not string[]
but K[]
, it means TS will narrow members of array to more specific types then string.
Upvotes: 1
Reputation: 2290
If your array is always contains only "a"
and "b"
, then you can define union type of string literals:
type MyUnionType = "a" | "b"
Then define variable foo
as MyUnionType[]
. The result is:
declare function myFunction
<Q extends MyUnionType[], T extends {[key: string]: Q}>
(keys: T) : {[key1 in keyof T]: {[key2 in MyUnionType]: Widget}}
Should work :)
But if your array is always consists of different strings, then it's impossible to implement such typing, because TypeScript is only design-time tool
Upvotes: 0