'TypeScript: get a property from conditional types

I'm trying to get a value that either can exist or not on the property. So I have 2 types: EmptyUser and UserResponse.

EmptyUser interface only has one property. UserResponse interface has a lot of properties AND id property that I need.

Then in my function I'm trying to use id, but I can't get it from the created types. Below is the example of code:

interface EmptyUser {
  // only this property
  unauthorized: boolean;
}

interface UserResponse {
  // ...a lot of different properties and
  id: number;
}

export type UsersType = EmptyUser | UserResponse;

interface State {
  users: UsersType,
}

then in my code I'm trying to get property id from state.users:

const { id }: UsersType = state.users;

and I receive an error: TS2339: Property 'id' does not exist on type 'UsersType'.

I would appreciate any help.



Solution 1:[1]

With | you are saying that UsersType can be any one of EmptyUser or UserResponse. So id can not be guaranteed to be in UsersType.

If you do it individually, with either one of the types you will not have an issue. Link

interface EmptyUser {
  // only this property
  unauthorized: boolean;
}

interface UserResponse {
  // ...a lot of different properties and
  id: number;
}

export type UsersType = UserResponse;

interface State {
  users: UsersType,
}

let state : State = {
  users : {
    id : 2
  }
};

const { id }: UsersType = state.users;

But if you want an item to have properties from both, you need & intersection type.

interface EmptyUser {
  // only this property
  unauthorized: boolean;
}

interface UserResponse {
  // ...a lot of different properties and
  id: number;
}

export type UsersType = EmptyUser & UserResponse;

interface State {
  users: UsersType,
}

let state : State = {
  users : {
    id : 2,
    unauthorized : false
  }
};

const { id }: UsersType = state.users;

Playground Link

Solution 2:[2]

Please try below code.

interface EmptyUser {
   // only this property
   unauthorized: boolean;
}

interface UserResponse {
   // ...a lot of different properties and
   id: number;
}

type UsersType = EmptyUser | UserResponse;

 interface State {
   users: UsersType,
 }

 let state : State = {
   users : {
      id : 2,
      unauthorized : false
   }
 };

const { id }  = state.users as UserResponse;
console.log(id);

Playground link

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tushar Shahi
Solution 2 Ganesan C