Eric Haynes
Eric Haynes

Reputation: 5786

How to use an indexed access type for children of an optional property?

Let's say I have a type like:

type Person = {
  firstName: string;
  lastName: string;
  contact: {
    type: string;
    value: string;
  }[];
};

If I want the type of an element of the contact array, I can use an indexed access type like:

type Contact = User['contact'][number];

// same as type Contact = { type: string; value: string };

In essence, "the type at a numeric index of the contacts array", and would also work for a nested object.

However, if that is an optional parameter such as:

type Person = {
  firstName: string;
  lastName: string;
  contact?: {
    type: string;
    value: string;
  }[];
};

This (validly) reports an error of:

Type '{ type: string; value: string; }[] | undefined' has no matching index signature for type 'number'.ts(2537)

How can I "null check" within the type alias to get a nested type?

Upvotes: 11

Views: 3928

Answers (2)

wegry
wegry

Reputation: 8147

Update

NonNullable<T> will remove undefined and null from its type parameter.

type Contact = NonNullable<User['contact']> // almost the same as the next type, but also excludes `null` from the union.
type Contact = Exclude<User['contact'], undefined>[number];

https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype

Older answer

You can Exclude types when you need to drill down more.

type Contact = Exclude<User['contact'], undefined>[number];

The docs aren't particularly stable around the subject, but https://www.typescriptlang.org/docs/handbook/utility-types.html is the current link.

Upvotes: 24

ryok90
ryok90

Reputation: 90

Wouldn't be easier and more readable to just type contact separately?

type Person = {
  firstName: string;
  lastName: string;
  contact?: PersonContact[];
};

type PersonContact = {
  type: string;
  value: string;
};

Upvotes: -2

Related Questions