Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: Define a union type from an array of strings

Tags:

typescript

I can't be the first person coming across this, but my searches have not turned up any useful leads yet. Would greatly appreciate some expert TypeScript advice.

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?

Bonus: How do I enforce that my fruitFacts object exhaust all the keys derived from the array as well, so that it specifies facts for Apples, Oranges, and Pears in the example above.

like image 468
Arash Motamedi Avatar asked Aug 29 '18 20:08

Arash Motamedi


People also ask

How do you convert an array into string literal union type in TypeScript?

To convert an array of strings into a string literal union type in TypeScript, you can first define the array of strings then make the array as readonly using the as const keyword, and then use the typeof operator on all the values contained in the array.

How do you declare a union type variable in TypeScript?

TypeScript 1.4 gives programs the ability to combine one or two types. Union types are a powerful way to express a value that can be one of the several types. Two or more data types are combined using the pipe symbol (|) to denote a Union Type.

How do you define a union in TypeScript?

In TypeScript, a union type variable is a variable which can store multiple type of values (i.e. number, string etc). A union type allows us to define a variable with multiple types. The union type variables are defined using the pipe ( '|' ) symbol between the types. The union types help in some special situations.

Should I use [] or array in TypeScript?

There is no difference at all. Type[] is the shorthand syntax for an array of Type . Array<Type> is the generic syntax. They are completely equivalent.


2 Answers

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

const fruits = ["Apple", "Orange", "Pear"] as const; type Fruits = 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.

like image 55
Ben Regenspan Avatar answered Sep 19 '22 10:09

Ben Regenspan


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]
like image 26
Titian Cernicova-Dragomir Avatar answered Sep 22 '22 10:09

Titian Cernicova-Dragomir