typescript - Finns det något sätt att specificera att en array innehåller både föräldra- och barnklassobjekt


Anta att jag har följande hierarki:

interface Cmp {
  guid: string;
}

interface ContainerCmp extends Cmp {
  layout: string;
}

Nu har jag en array med objekt som kan vara antingen av typen Cmp eller ContainerCmp. Det betyder att vissa objekt i arrayen saknar layout-egenskapen.

Just nu tillåter inte TypeScript mig att specificera båda typerna för items:

const items: Cmp[] | ContainerCmp[] = [];
items.forEach((item) => {
  if (isContainerCmp(item)) {
    console.log(item.layout);
  }
});

genererar ett fel:

Error:(28, 1) TS2349:Cannot invoke an expression whose type lacks a call signature. 
Type '{ (callbackfn: (this: void, value: Cmp, index: number, array: Cmp[]) => void): void; 
(callbackfn:...' has no compatible call signatures.

Så jag specificerar den översta Cmp-typen och använder typvakter:

const items: Cmp[] = [];
items.forEach((item) => {
  if (isContainerCmp(item)) {
    console.log(item.layout);
  }
});

function isContainerCmp(cmp: Cmp | ContainerCmp): cmp is ContainerCmp {
  return (<ContainerCmp>cmp).layout !== undefined;
}

Jag undrar om det är rätt tillvägagångssätt och om det finns något annat sätt att specificera båda typerna för arrayen items?

Svar #1

Det här är en array som endast har Cmp eller endast ContainerCmp.

const items: Cmp[] | ContainerCmp[] = [];

Detta är en array som har både Cmp och ContainerCmp.

const items: (Cmp | ContainerCmp)[] = [];
// or
const items: Array<Cmp | ContainerCmp> = [];

REDIGERA: Lagt till @NitzanTomer förslag till svaret.