Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I extract a type from an array in typescript?

Is there a way to declare a type in typescript that 'extracts' the inner type of an array?

Example:

Let's say I already have something like this in my codebase:

export interface Cache {
    events: Event[],
    users: User[]
}
type CacheType = Event[] | User[];

//or maybe: 
//   type TypeOfProperty = T[keyof T];
//   type CacheType = TypeOfProperty<Cache>; 

What I want is something which would be equivalent to this:

type InnerCacheType = Event | User;

But without manually retyping it every time I add something to Cache or CacheType

Is this possible in Typescript?

like image 326
Lennart Hoffmann Avatar asked Apr 21 '17 08:04

Lennart Hoffmann


People also ask

How do you find the type of an array?

Array types may be identified by invoking Class. isArray() . To obtain a Class use one of the methods described in Retrieving Class Objects section of this trail.

Is array type TypeScript?

An array is a special type of data type which can store multiple values of different data types sequentially using a special syntax. TypeScript supports arrays, similar to JavaScript.

How do you declare an array of types in TypeScript?

Summary. In TypeScript, an array is an ordered list of values. An array can store a mixed type of values. To declare an array of a specific type, you use the let arr: type[] syntax.

What is the type of array of objects in TypeScript?

Inline Type for Array of Objects in TypeScript The array of objects is defined inside the curly brackets {} . The array of objects can be defined using inline type.


3 Answers

This is possible with Typescript 2.8+. You can declare an Unpacked<T> type as follows:

type Unpacked<T> = T extends (infer U)[] ? U : T;

Now you can do

type InnerCacheType = Unpacked<CacheType>; // Event | User

This is a condensed definition of the Unpacked type given in the documentation.

like image 84
Ingo Bürk Avatar answered Oct 19 '22 18:10

Ingo Bürk


This could also be achieved with a type query. ie.

type CacheType = Event[] | User[];
type InnerCacheType = CacheType[number]; // Event | User

TS Playground

If you look at this comment from the ts dev team

You're allowed to write

const t: Array<string>[number] = "hello";

as a roundabout way of writing const t: string

So This will always hold true.

like image 33
lonewarrior556 Avatar answered Oct 19 '22 19:10

lonewarrior556


Let's assume that you can use TypeScript 2.1 or greater, otherwise there is no way to achieve what you're looking for.

Also, keep in mind that you're taking for granted that all the properties of the Cache interface will be arrays. If this is not the case, your question becomes senseless, so I will also make this assumption.

Generally speaking, CacheType can be written as

type CacheType = Cache[typeof Cache];

including any inherited properties. The obtained type is equivalent to Event[] | User[], however extracting the array components from such union type is unfeasible.

The solution is using mapped types. The InnerCacheType you are looking for can be written as

type InnerCacheType = MappedCacheType[typeof MappedCacheType];

where

type MappedCacheType = { [P in keyof Cache]: Cache[P][0]; };

In fact, the last type is equivalent to

{ events: Event; users: User; }

Please notice that TypeScript keeps the names the same as the original ones.

Summarizing, without considering your use case, the way to express the component type of an array type T is T[0].

like image 4
FstTesla Avatar answered Oct 19 '22 20:10

FstTesla