2

I have this literal type export type names = 'n1' | 'n2' | 'n3' | 'n4' | 'n5' | 'n6';

I wonder how would you iterate that type ?

May be you can convert that type in something else and iterate that?

Should you redefine the type in a different way?

names.forEach(value => {
  console.log(value);
}); 
4
  • 2
    What do you mean, "iterate type"? A type does not exist in the compiled Javascript Commented Apr 1, 2020 at 1:25
  • I don't think you can enumerate the types in a type declaration like that; you could change it to a string enum though, and then you should be able to enumerate the values. Commented Apr 1, 2020 at 1:27
  • @DaveCousineau do you have a sample? Commented Apr 1, 2020 at 1:28
  • Possible duplicate of TypeScript String Union to String Array. You should define the names array first and have the compiler infer the names type from it, not the other way around (which is not possible) Commented Apr 1, 2020 at 1:30

2 Answers 2

8

Short Answer

You could define it as a const and a type like this:

const names = ['n1' , 'n2' , 'n3' , 'n4' , 'n5' , 'n6'] as const;

// This produces the union type 'n1' | 'n2' | 'n3' | 'n4' | 'n5' | 'n6';
type names = typeof names[number];

// use names as a type here
const n1: names = 'n1';

console.log({
  names,
  n1,
  // use names as an array here
  mapped: names.map(name => `I am ${name}`)
});

Explanation and Demo

What is going on here?

The as const creates an array with a const context. That means the array is not a string array but is a readonly array of specific string literal values.

Then, the typeof names[number] uses an indexed access operator to extract those string literal values into a union type.

If we did not use as const to define our array, then the typeof names[number] would give us string type instead of a union of the array's string literal values.

The end result is pretty neat. We can use names as a union type for type checking and as an array at runtime.

Here it is in the playground, and here is the playground output in JavaScript:

"use strict";
const names = ['n1', 'n2', 'n3', 'n4', 'n5', 'n6'];
const n1 = 'n1';
console.log({
names,
n1,
mapped: names.map(name => `I am ${name}`)
});

Caveat: The use of names as both a union type an an array value raises a question about naming conventions. Usually types are PascalCased (e.g. Names) and values are camelCased (e.g. names). Which naming conventions ought we to follow here?

For completeness, here is how it looks in VS Code across two files:

enter image description here

Sign up to request clarification or add additional context in comments.

8 Comments

why do you need this line type names = typeof names[number]; ?
@sreginogemoh the typeof names[number] uses an indexed access operator to get the string literal types of the array values.
seems like there is something wrong with names.forEach(name => name) if you check the playground url it output Array(6) [ "n1", "n2", "n3", "n4", "n5", "n6" ] n1 undefined
@sreginogemoh Nice catch. Fixed.
@sreginogemoh const names and type names have the same name, because I read your requirements as 1. define a string literal type and 2. enable iterating over that string literal "type". We did that by giving const names and type names the same name. That way we fulfill (1) by creating a type, and we fulfill (2) by creating a value with the same name as the type.
|
3

Types do not exist in the compiled code - there is nothing emitted to iterate over.

If you need the union type as shown in the question and need to be able to iterate over it as an array, first create the array as const, and define the type as the array's values:

const arr = ['n1', 'n2', 'n3', 'n4', 'n5', 'n6'] as const;
export type names = typeof arr[number];
for (const num of arr) {
  console.log(num);
}

4 Comments

why do you need this like export type names = typeof arr[number]; ?
typeof arr[number] will give you the type of accessing a number property on the arr - eg arr[0], arr[1], etc, and those accesses result in a value of 'n1', or 'n2', etc - it creates a union type of all values in the array.
i just removed export type names = typeof arr[number]; seems like for loop still works...
If you don't actually need the type union described in the question, then feel free to remove it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.