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:
