103

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, but is there something similar for values?

1
  • 5
    type foo = Array<T> - is this question asking how to get "T", or something else? Commented Sep 23, 2017 at 5:48

7 Answers 7

152

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

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

or

type FooItem = Foo[number];
Sign up to request clarification or add additional context in comments.

Comments

74

Starting with TypeScript 2.8, you can also do this with the infer keyword. This should only be used for more complicated cases (arrays nested in promises, etc.). Otherwise, it is overly verbose.

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 returned 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 }]>;

1 Comment

Note that this only works with mutable Arrays.
11

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

type Foo = Array<{ name: string; test: number; }>
type Bar = Foo[number]; // <- What you want
// Then you can use it as follows
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';

Comments

7

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>

It was inspired by yeerk.

Comments

6

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: Advanced Types

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

Comments

4

Using the popular utility-types library:

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

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

Comments

3

Despite Aleksey's 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.

5 Comments

Currently there is no way to extract the param of a generic type. Well, for an array, the generic type is the same as type of the member at any index, which you can extract, using the "indexed access operator".
@torazaburo by querying the type of an array member you're extracting the member type from an instance of that array type, not from the generic array type itself which is not possible in the current version of TypeScript AFAIK.
I think you're confused between the run-time typeof result, and the TypeScript type of an array element.
@torazaburo I see what you mean, the member type is being extracted from the type after all even though I can only query its member type from a context that have an instance of Foo instead of extracting it "directly" from Foo. Also I tried to improve the wording in my answer. Thanks for the heads-up!
Please provide the text/code as well. See e.g., Why should I not upload images of code/data/errors?. But please, *** *** *** *** *** without *** *** *** *** *** "Edit:", "Update:", or similar.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.