Home > Software engineering >  Typescript converting nested array into type
Typescript converting nested array into type

Time:10-14

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 strings 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;
//     };
// }

Playground

  • Related