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:
