Reputation: 5208
How can I iterate a string literal type in typescript?
For example i define this type
type Name = "Bill Gates" | "Steve Jobs" | "Linus Torvalds";
I want to iterate like this
for (let name of Name) {
console.log("Possible name: " + name);
}
Or is this simply not possible in typescript?
Upvotes: 84
Views: 43167
Reputation: 1223
Rather than iterating a (union of) string literal types as the OP requested, you can instead define an array literal and if marked as const
then the entries' type will be a union of string literal types.
Since typescript 3.4 you can define const assertions on literal expressions to mark that:
For example:
const names = ["Bill Gates", "Steve Jobs", "Linus Torvalds"] as const;
type Name = typeof names[number];
Iterating that at runtime:
for(const n of names) {
const val : Name = n;
console.log(val);
}
It can often be more useful to define it as an object, especially if there's value information to associate to the entries:
const companies = {
"Bill Gates" : "Microsoft",
"Steve Jobs" : "Apple",
"Linus Torvalds" : "Linux",
} as const;
type Person = keyof typeof companies;
type Company = typeof companies[Person];
for(const n of names) {
const p : Person = n;
const c : Company = companies[p];
console.log(p, c);
}
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions
https://mariusschulz.com/blog/const-assertions-in-literal-expressions-in-typescript
https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html
Upvotes: 98
Reputation: 41
To add to @Paul Thompson's answer, a pattern I'm trying (to consolidate a large model that we want safety for at compile and runtime) is:
// GiftBasket.ts
// Before:
export type Fruit = 'Apple' | 'Banana';
// After:
export class GiftBasketForm {
// ...
edibleGift: Fruit,
bonusGift: Toy | Fruit,
// ...
static AllowedValues: Record<string, readonly string[]> = {
Fruit: [ 'Apple', 'Banana' ] as const,
// ... a lot of models/allowed values to organize
}
}
export type Fruit = typeof GiftBasketForm.AllowedValues.Fruit[number]
// Now you can both:
const fruitSafeAtCompileTime: Fruit = 'Apple';
const myFormAllowedValuesAtRuntime: Fruit[] = GiftBasketForm.AllowedValues.Fruit;
// Or an example case where you might use both at once:
const makeRandomFruit: Fruit = getRandom(GiftBasketForm.AllowedValues.Fruit);
Upvotes: 1
Reputation: 1718
You can't by using Union types. But you can do it with enums:
enum Name {
'Bill Gates' = 'Bill Gates',
'Steve Jobs' = 'Steve Jobs',
'Linus Torvalds' = 'Linus Torvalds'
}
for (const name of Object.keys(Name)) {
console.log('Possible name: ' + name)
}
Upvotes: 4
Reputation: 9248
Since TypeScript is just a compiler, none of the typing information is present at runtime. This means that unfortunately you cannot iterate through a type.
Depending on what you're trying to do it could be possible for you to use enums to store indices of names that you can then retrieve in an array.
Upvotes: 23
Reputation: 5208
Since typescript 2.4 it is possible to use string typed enums. These enums can easily be iterated:
https://blogs.msdn.microsoft.com/typescript/2017/06/27/announcing-typescript-2-4/
Upvotes: 3
Reputation: 5617
AFAIK there is no way to "lift" a string union (type) to runtime JS (value).
The closest solution I found was to use enum
: example / related issue.
Upvotes: 3