zzandy
zzandy

Reputation: 2353

How to define mapped type based on an array in typescript?

Is it possible to define this function

function magic(...propertyNames:string[]): { ????? : any }
{
....
}

In such away that returned type would have properties as listed in propetyNames?

For example:

type ResultType = {alpha:any, bravo:any};

let res = magic('alpha', 'bravo'); // res is compatible with ResultType

Upvotes: 2

Views: 1388

Answers (1)

ford04
ford04

Reputation: 74820

Here is a possible solution that can make magic happen:

declare function magic<T extends string[]>(
  ...propertyNames: T
): Record<T[number], any>;

const result = magic("alpha", "bravo");

type ResultType = typeof result; // {alpha: any; bravo: any;}

Testing of ResultType:

const t1: ResultType = {
  alpha: "foo",
  bravo: 42,
  wannaBe: 3 // error (OK)
};

You could then further restrict the any type in Record<T[number] any> with an additional type parameter, as any doesn't provide any useful typing.

declare function magic<T extends string[], R>(
  ...propertyNames: T
): Record<T[number], R>;

Some explanation

  • T[number] gives us all item values as union type. E.g.
type T = ["alpha", "bravo"]
type TItems = T[number] // "alpha" | "bravo"
  • Record makes sure, that we have all item values "alpha" | "bravo" as property keys.
  • The tuple type can be inferred with help of generic rest parameters.

Playground

Upvotes: 4

Related Questions