wlf
wlf

Reputation: 3413

Why are these structurally similar types incompatible?

If I declare the following types:

export type Type1 = { id: string } | { id: number };
export type Type2 = { id: string } | { id: number };

Why do I get an error when used in the following manner:

function displayItem(item: Type1) {
  loadItem({ id: item.id });          // error is indicated here
}

function loadItem(item: Type2) {}

enter image description here

My understanding from https://www.typescriptlang.org/docs/handbook/type-compatibility.html is that they should be equivalent as they are structurally the same.

Simpler repro in light of answers (second type is not needed):

export type Type1 = { id: string } | { id: number };

function displayItem(item: Type1) {
   loadItem({ id: item.id });          // error is indicated here
}

function loadItem(item: Type1) {}

Upvotes: 3

Views: 331

Answers (2)

Bunyamin Coskuner
Bunyamin Coskuner

Reputation: 8859

It is not that Type1 is not equivalent to Type2

For example, following will not give an error

function displayItem(item: Type1) {
  loadItem(item);
}

function loadItem(item: Type2) {}

The problem arises when you type item.id which could be two things. Since Type1 is defined as export type Type1 = { id: string } | { id: number }; the type of this variable could be string or number. So typescript creates another type for {id: item.id} which is {id: number | string} as you can see it is not compatible with Type2.

You have to explicitly write which type you'd like to use.

Following won't give any error

function displayItem(item: Type1) {
  loadItem({ id: item.id as number});         
}

Now, I mark item.id as number so type of { id: item.id as number} is {id: number} which is compatible with Type2

Just change your types to following

export type Type1 = { id: string | number};
export type Type2 = { id: string | number};

Upvotes: 3

VRoxa
VRoxa

Reputation: 1051

In depth, you are trying to assing a value of type number | string to either number or a string.

Since you are accessing item.id, id can be string or number, by your type definition. Your Type2 expects an object {id: string} or {id: number} which is different from {id: string | number}.

So, two different scenarios could resolve this mishap.

  1. Declare your Type2 to expect one key called id which is number | string
  2. Pass the whole item object to your second function. This is the so-called type compatibility

Upvotes: 3

Related Questions