Home > Enterprise >  how to access nested array type in typescript
how to access nested array type in typescript

Time:04-14

I want to extract a sub-type from an interface in typescript like below

interface components {
  schemas: {
    a: {
      b?: Array<{
        c?: {
          d?: string;
        };
      }>;
    };
  }
// I want to export

export type custom = components["schemas"]["a"]["b"][number]["c"]

however I get an error at [number] saying Type '{ c?: { d?: string | undefined; } | undefined; }[] | undefined' has no matching index signature for type 'number'.ts(2537)

How do we achieve this?

CodePudding user response:

Here is what I came up with:

type Increment<A extends number[]> = [...A, 0];

type DeepRequired<T, D extends number = -1, R extends number[] = []> =
T extends object ? R["length"] extends D ? T : {
    [K in keyof T]-?: DeepRequired<T[K], D, Increment<R>>;
} : T;

Let's look at DeepRequired without the extra bits:

type DeepRequired<T> = T extends object ? {
    [K in keyof T]-?: DeepRequired<T[K]>;
} : T;

This type is simple at its core; it's simply traversing the entire object and making all properties required.

This does work without errors:

type T = DeepRequired<components>["schemas"]["a"]["b"][number]["c"];

But you'll notice T's "d" property is required too, which might not be the desired result. That's why it's a lot more complicated; it limits the depth at which it makes properties required.

Back to our original snippet, a utility type Increment is created to increment the depth we are at, and the new parameters for DeepRequired include the specified depth (optional), and the current depth it is at.

Before it makes all properties required, it checks if it exceeds the depth specified, and if it does, it stops.

This now works as expected:

type T = DeepRequired<components, 5>["schemas"]["a"]["b"][number]["c"];

Playground

CodePudding user response:

I really like @kellys' answer for the part of the DeepRequired, but if the goal for the result is string | undefined, I don't like the part where a number (the depth) has to be hardcoded so I can suggest the following approach

type Path<T, K> = K extends [any, ...any]
  ? (K extends [keyof NonNullable<T>, ...infer RR]
    ? Path<NonNullable<T>[K[0]], RR>
    : never)
  : T


export type custom = Path<components, ['schemas', 'a', 'b', number, 'c', 'd']>

TS Playground

  • Related