---
description: Extract the type of an element inside an array property, even when
  the property is optional.
keywords:
  - typescript
  - types
  - utility types
  - array element type
publishDate: 2025-10-02
shortTitle: Get Array Element Type Safely
tags:
  - TypeScript
title: "TypeScript: Get the Element Type of an Array Property Safely"
---

Types you do not control show up everywhere.

API responses. GraphQL codegen. Third-party libs.

And they love this pattern: an array, buried inside a type, sometimes optional.

When that happens, you usually do not want the array type.

You want the element type.

TypeScript makes the simple case easy. Strict mode is where it gets fun.

This post walks through the common approaches and ends with a strict-safe helper you can reuse.

## Step 0: Index the array type

If the array property is required, index it with `number`.

```ts twoslash
interface Store {
  orders: { id: string; total: number }[];
}

type Order = Store["orders"][number];
//   ^?
```

Why this works:

- `Store["orders"]` is an array type.
- Indexing an array type with `number` gives you the element type.

Use this when the property is always present.

## Step 1: Generalize for any array

Extract an element type from any array or tuple with a conditional type.

```ts twoslash
type ElementOf<T> = T extends readonly unknown[] ? T[number] : never;

type Num = ElementOf<number[]>;
//   ^?
type Tuple = ElementOf<[1, 2, 3]>;
//   ^?

interface Store {
  orders: { id: string; total: number }[];
}

type Order = ElementOf<Store["orders"]>;
//   ^?
```

> [!NOTE]
> Use `readonly unknown[]` so the utility works with both mutable arrays (`T[]`) and readonly arrays (`readonly T[]`).

This covers raw arrays and tuples.

Now let's point it at a specific property.

## Step 2: Target an object property

Add a key parameter so you can point at a specific property.

```ts twoslash
interface Store {
  orders: { id: string; total: number }[];
}

type ElementOf<T, K extends keyof T> = T[K] extends readonly unknown[]
  ? T[K][number]
  : never;

type Order = ElementOf<Store, "orders">;
//   ^?
```

This works while the property type stays a pure array.

Then optional shows up.

## Step 3: Handle optional properties in strict mode

With `strictNullChecks`, optional properties include `undefined`.

That changes the type.

And it breaks Step 2 because a union like `X[] | undefined` does not extend `readonly unknown[]`.

```ts twoslash
interface Store {
  orders?: { id: string; total: number }[];
}

type ElementOf<T, K extends keyof T> = T[K] extends readonly unknown[]
  ? T[K][number]
  : never;

// @warn: Order is not what we expect.
type Order = ElementOf<Store, "orders">;
//   ^?
```

At this point, `Order` becomes `never`.

This is the key idea: you cannot index into a union that includes `undefined` using this check.

So fix the union first.

## Step 4: One helper that covers both cases

This version supports:

- raw arrays: `ElementOf<number[]>`
- object properties: `ElementOf<Store, "orders">`
- optional array properties under `strictNullChecks`

```ts twoslash
interface Store {
  orders?: { id: string; total: number }[];
}

type ElementOf<T, K extends keyof T = never> = [K] extends [never]
  ? T extends readonly unknown[]
    ? T[number]
    : never
  : Extract<T[K], readonly unknown[]>[number];

// @annotate: Order is what we expect.
type Order = ElementOf<Store, "orders">;
//   ^?
```

### Why the mode switch works

`K` defaults to `never`.

- If you do not pass a key, you want raw array mode.
- If you pass a key, you want property mode.

The tuple check avoids distribution issues:

- `[K] extends [never]` stays stable
- `K extends never` can behave badly with unions

### Why `Extract` works

When a key is provided:

- `T[K]` might be `{ ... }[] | undefined`
- `Extract<T[K], readonly unknown[]>` keeps only the array part
- indexing with `[number]` returns the element type

That is the whole fix.

## Edge cases

For non-array properties, the helper returns `never`.

```ts twoslash
interface Store {
  name: string;
}
// ---cut-start---
type ElementOf<T, K extends keyof T = never> = [K] extends [never]
  ? T extends readonly unknown[]
    ? T[number]
    : never
  : Extract<T[K], readonly unknown[]>[number];
// ---cut-end---

type Invalid = ElementOf<Store, "name">;
//   ^?
```

If you prefer an error instead of `never`, you can build a stricter variant later.

Returning `never` keeps the utility lightweight and composable.

## Recap

Use the simplest tool that fits:

- Required array property: `T["prop"][number]`
- Raw arrays and tuples: `ElementOf<T>`
- Optional array property: `ElementOf<T, "prop">` with `Extract`

That's it. Short syntax for the common case, strict-safe behavior for the optional case.