Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create a typescript type from an array?

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 ?

like image 378
aherve Avatar asked Mar 06 '19 09:03

aherve


People also ask

How do you give an array a type?

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> .

Is array a data type in TypeScript?

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.

How do you define an array of type in TypeScript?

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'];

Can arrays be of any type?

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.


Video Answer


1 Answers

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.

like image 164
Titian Cernicova-Dragomir Avatar answered Sep 28 '22 04:09

Titian Cernicova-Dragomir