typescript - Varför är dessa strukturellt liknande typer inkompatibla?


Om jag deklarerar följande typer:

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

Varför får jag ett fel när det används på följande sätt:

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

function loadItem(item: Type2) {}

Min förståelse från https://www.typescriptlang.org/docs/handbook/type-compatibility.html är att de bör vara likvärdiga eftersom de är strukturellt desamma.

Enklare återgivning med tanke på svaren (andra typen behövs inte):

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

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

function loadItem(item: Type1) {}

Svar #1

På djupet försöker du tilldela ett värde av typen number | string till antingen number eller en string.

Eftersom du får åtkomst till item.id, kan id vara string eller number, enligt din typdefinition. Din Type2 förväntar sig ett objekt {id: string} eller {id: number} vilket är annorlunda än {id: string | number}.

Så, två olika scenarier skulle kunna lösa denna missöde.

  1. Deklarera din Type2 för att förvänta en nyckel som heter id som är number | string
  2. Skicka hela item-objektet till din andra funktion. Detta är det så kallade typkompatibilitet.

Svar #2

Det är inte så att Type1 inte är ekvivalent med Type2

Till exempel kommer följande inte att ge ett fel

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

function loadItem(item: Type2) {}

Problemet uppstår när du skriver item.id vilket kan vara två saker. Eftersom Type1 är definierad som export type Type1={ id: string } | { id: number }; kan typen på denna variabel vara string eller number. Så TypeScript skapar en annan typ för {id: item.id} som är {id: number | string}, och som du kan se är den inte kompatibel med Type2.

Du måste uttryckligen skriva vilken typ du vill använda.

Följande kommer inte att ge något fel

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

Nu markerar jag item.id som number så typen av { id: item.id as number} är {id: number} vilket är kompatibelt med Type2

Ändra bara dina typer till följande

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

Relaterade artiklar