Reputation: 10682
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
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
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