Arash Motamedi
Arash Motamedi

Reputation: 10682

Define a union type from an array of strings

Say I have an array:

const fruits = ["Apple", "Orange", "Pear"];

and I want to define an object mapping each fruit to some fun facts about it:

interface Facts {
    color: string,
    typicalWeight: number
}

const fruitFacts: { [key: members of fruits]: Facts } = {
    "Apple": { color: "green", typicalWeight: 150 }
    //
}

How do I do that [key: members of fruits] part?

Upvotes: 118

Views: 43546

Answers (2)

Ben Regenspan
Ben Regenspan

Reputation: 10548

TypeScript 3.4 added const assertions which allow for writing this as:

const fruits = ["Apple", "Orange", "Pear"] as const;
type Fruit = typeof fruits[number]; // "Apple" | "Orange" | "Pear"

With as const TypeScript infers the type of fruits above as readonly["Apple", "Orange", "Pear"]. Previously, it would infer it as string[], preventing typeof fruits[number] from producing the desired union type.

Upvotes: 214

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249646

It can be done but first you need an extra function to help infer the string literal type for the array elements. By default Typescript will infer string[] for an array even if it is a constant. After we have an array of string literal types we can just use a type query to get the desired type

function stringLiteralArray<T extends string>(a: T[]) {
    return a;
}

const fruits = stringLiteralArray(["Apple", "Orange", "Pear"]);
type Fruits = typeof fruits[number]

Since 3.4 you can also use a const type assertion instead of the stringLiteralArray function:

const fruits = ["Apple", "Orange", "Pear"] as const;
type Fruits = typeof fruits[number]

Upvotes: 30

Related Questions