This seems very basic but I'm not having any luck finding an answer.
I would like to call a function like this:
const result = myFunction({
'keyA': [ 'arrayA1', 'arrayA2' ],
'keyB': [ 'arrayB1', 'arrayB2' ],
});
I would like the result to be a key/value Record, where the keys are limited to keyA
and keyB
, and the value are also key/value records, with keys as arrayA1
, arrayA2
, etc:
result = {
keyA: {
arrayA1: 'example',
arrayA2: 'example',
},
keyB: {
arrayB1: 'example',
arrayB2: 'example',
}
}
I'm struggling to come up with a generic function signature that will take the keys and array items in the parameter and turn them into the nested object keys.
function myFunction<
T extends { [K in keyof T]: string[] },
S extends keyof T,
O extends T[K] // ???
//O extends { InstanceType<T[K]> } // nope
//O extends { [K in keyof T]: { [K2 in keyof T[K]]: K2 } } // very confused
>(structure: T): Record<S, Record<O, string>> { ... }
I can't seem to work out how to extract the nested string array, and convert it into a type specifying only those values as permitted strings. What am I missing?
CodePudding user response:
Your function needs only two generic types:
function myFunction<
T extends Record<string, S[]>,
S extends string
>(structure: T): {
[K in keyof T]: {
[K2 in T[K][number]]: string
}
} { return null! }
T
will hold the passed structure
and is constrained to be an object with string keys where the values are S
-arrays. S
is constrained to be a string
. We need S
here to narrow down the type of the string
s in the array to string literals.
The return type consists of two nested mapped types. The first one maps over the keys of T
while the second one maps over the elements in T[K]
.
const result = myFunction({
'keyA': [ 'arrayA1', 'arrayA2' ],
'keyB': [ 'arrayB1', 'arrayB2' ],
});
// const result: {
// keyA: {
// arrayA1: string;
// arrayA2: string;
// };
// keyB: {
// arrayB1: string;
// arrayB2: string;
// };
// }