Home > Enterprise >  Typescript: Form an Object from String Array
Typescript: Form an Object from String Array

Time:05-26

i want to ask is there any way to form a function in typescript that can enable autocomplete when using array.reduce?

ex:

function formObject<T>(arr: T[]): ?? {
  return arr.reduce((memo, val) => {
    memo[val] = 'test'
    return memo
  }, {})
}

const array = ["foo", "bar"]
const object = formObject(array);
const testObject2 = formObject(["another"])

hoping that i will get autocomplete for object like this

const a = object.foo  // type string and foo is autocomplete
const b = object.bar // type string and bar is autocomplete

const c = testObject2.another // type string and another is autocomplete

const d = object.another // return type error because there's no another in object

CodePudding user response:

This is certainly possible. The question is if you really need this...

We can create a generic type StringArrToObject which takes a tuple T and creates an object with every element of T as a key.

type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;

type StringArrToObject<T extends string[]> = Expand<{
  [K in keyof T as T[K] extends string ? T[K] : never]: string
}>

Don't mind the Expand type here. This is just there to make the type prettier.

We can now use this in the function formObject.

function formObject<
  T extends string[]
>(arr: readonly [...T]): StringArrToObject<T> {
  return arr.reduce((memo, val) => {
    memo[val] = 'test'
    return memo
  }, {} as Record<string, any>) as any
}

Let's see this function in action:

const array = ["foo", "bar"] as const
const obj = formObject(array);
// const obj: {
//     foo: string;
//     bar: string;
// }


const testObject2 = formObject(["another"])
// const testObject2: {
//     another: string;
// }

Important detail here: See how we have to use as const for the array variable. Otherwise the type information about specific elements will be lost.

Playground


But keep in mind: This type implementation only works for this specific array.reduce() implementation. If you change the logic inside the function, you will also have to change the type to reflect the changed behaviour. So this is not a generic type that would work for any reduce implementation.

  • Related