Alex Ngo
Alex Ngo

Reputation: 985

How to get type of array items?

If I have a type type foo = Array<{ name: string; test: number; }>, would it be possible to get the type of the values within the array, in this case, the interface. I know there is keyof to get the keys, is there something similar for values?

Upvotes: 94

Views: 93655

Answers (7)

Nicky McCurdy
Nicky McCurdy

Reputation: 19524

This works with any iterable (including readonly Arrays and tuples):

type ElementType<T extends Iterable<any>> = T extends Iterable<infer E>
  ? E
  : never;

Usage:

ElementType<typeof foo>

Inspired by yeerk

Upvotes: 5

Flavien Volken
Flavien Volken

Reputation: 21259

You can simply get the type of the array using the brackets as follow:

type Foo = Array<{ name: string; test: number; }>
type Bar = Foo[number]; // <- what you want
// then you can use as follow
const bar: Bar = {name:"", test:42};

Bonus:

If your array was a tuple (where elements are typed by index), you can specify which type you want to target using the index within the type's brackets.

type foo = [number, string, ...number[]]; // a tuple or typed array
const barA: foo[0] = 42;
const barB: foo[1] = 'hello';
const barC: foo[2] = 256;
// Using type[number] will generate an union of all the possible types.
// Here below string | number. The following is therefore valid
const barStringOrArray: foo[number] = Math.random() < 0.5 ? 42 : 'hello';

Upvotes: 11

yeerk
yeerk

Reputation: 2667

Starting with TypeScript 2.8 you can also do this inline with the infer keyword:

type GetElementType<T extends any[]> = T extends (infer U)[] ? U : never;

For example:

// ElementType === string
type ElementType = string[] extends (infer U)[] ? U : never;

The infer keyword is very powerful and can extract any type out of larger type. For example if the type was a function that returns an array:

type FncType = () => [{ name: string }];

// Output === { name: string }
type Output = FncType extends () => (infer U)[] ? U : never;

You can also use the infer keyword in generic types:

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

// Output === { name: string }
type Output = GetArrayReturnType<() => [{ name: string }]>;

Upvotes: 73

juno su&#225;rez
juno su&#225;rez

Reputation: 61

Using the popular utility-types library:

type foo = Array<{ name: string; test: number; }>

type fooElements = ValuesType<foo>
// = { name: string; test: number; }

See https://www.npmjs.com/package/utility-types#valuestypet

Upvotes: 4

Aleksey L.
Aleksey L.

Reputation: 37918

If you're looking to how to extract { name: string; test: number; } type, you can simply create alias to "item at index":

type Foo = Array<{ name: string; test: number; }>;
type FooItem = Foo[0];

or

type FooItem = Foo[number];

Upvotes: 146

Shaun Luttin
Shaun Luttin

Reputation: 141434

We can also use an indexed access operator like this:

const someArray = [
    {
        foo: '',
        bar: '',
        baz: ''
    },
    {
        foo: '',
        bar: '',
        baz: ''
    }
];

// indexed access operator
type SomeArray = typeof someArray[number];

There is a write-up on those here: https://www.typescriptlang.org/docs/handbook/advanced-types.html

The second operator is T[K], the indexed access operator.

Upvotes: 6

cvsguimaraes
cvsguimaraes

Reputation: 13230

Despite Aleksey answer, it might be useful to know that if the instance of that generic type exposes at least one member of the type you want to extract, you could use typeof to query the type of that member.

For a generic Array the type can be queried from any array item: enter image description here

Note that line 27 only exists at design time so that will not generate any errors even if arr is empty or undefined at runtime.

Upvotes: 3

Related Questions