I often use code such as
export type Stuff = 'something' | 'else'
export const AVAILABLE_STUFF: Stuff[] = ['something', 'else']
This way I can both use the type Stuff
, and iterate over all the available stuffs if need be.
This works, but it feels like repeating twice the information. And you have to be careful because an update of either Stuff
or AVAILABLE_STUFF
also requires an update of its counterpart.
Is there a better way to define the type from the Array, or even to somewhat use the array to type some data ?
To create an array type you can use Array<Type> type where Type is the type of elements in the array. For example, to create a type for an array of numbers you use Array<number> . You can put any type within Array<Type> .
In typescript, an array is a data type that can store multiple values of different data types sequentially. Similar to JavaScript, Typescript supports array declaration and there are multiple ways to do it.
An array in TypeScript can contain elements of different data types using a generic array type syntax, as shown below. let values: (string | number)[] = ['Apple', 2, 'Orange', 3, 4, 'Banana']; // or let values: Array<string | number> = ['Apple', 2, 'Orange', 3, 4, 'Banana'];
You can create an array with elements of different data types when declare the array as Object. Since System. Object is the base class of all other types, an item in an array of Objects can have a reference to any other type of object.
One built-in option would be to use an enum instead of the type and array approach.
export enum Stuff {
something = 'something',
else = 'else',
}
export const AVAILABLE_STUFF: Stuff[] = Object.values(Stuff);
Another option is to extract the type from the type of AVAILABLE_STUFF
. To do this we must force the compiler to infer a tuple of string literals for AVAILABLE_STUFF
. This can be done in 3.4
with as const
or before 3.4
using an extra function. After AVAILABLE_STUFF
is a tuple type we can just use a type query to get the type of the elements:
export const AVAILABLE_STUFF = (<T extends string[]>(...o: T)=> o)('something', 'else'); // typed as ["something", "else"]
// export const AVAILABLE_STUFF = ['something', 'else'] as const; // typed as ["something", "else"] in 3.4
export type Stuff = typeof AVAILABLE_STUFF[number] //"something" | "else"
A few explanations of the above code. typeof AVAILABLE_STUFF
gives us the type of the constant (["something", "else"]
) to get the [number]
is called a type query and will give us the type of an item in the tuple.
The (<T extends string[]>(...o: T)=> o)
is just an IIFE we use to force the compiler to infer a string literal tuple type. It has to be generic as the compiler will only infer literal types and tuples in certain cases (a type parameter with a constraint of string
being one of them). The as const
version is what I would recommend using when it becomes available as it is more readable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With