Typescript-union på arrayer av objekter


Rotete rundt med en forening av arrays som inneholder objekter. Forventet at TS kan beskytte riktig type, men jeg antar at jeg mangler noe her:

type A = ReadonlyArray<
  | { readonly __typename: 'EmbedParagraph' }
  | { readonly __typename: 'EntityQueueParagraph' }
  | null
> | null;

type B = ReadonlyArray<
  | { readonly __typename: 'EmbedParagraph' }
  | {
      readonly __typename: 'EntityQueueParagraph';
      readonly id: string | null;
      readonly title: string | null;
    }
  | null
> | null;

function test(paragraphs: A | B) {
  paragraphs?.forEach((paragraph) => {
    /**
     * TS OUTPUT:
     * (parameter) paragraph: {
     *     readonly __typename: "EmbedParagraph";
     * } | {
     *     readonly __typename: "EntityQueueParagraph";
     * } | {
     *     readonly __typename: "EmbedParagraph";
     * } | {
     *     readonly __typename: "EntityQueueParagraph";
     *     readonly id: string | null;
     *     readonly title: string | null;
     * } | null
     */
    if (paragraph?.__typename === 'EntityQueueParagraph') {
      console.log(paragraph);
      /**
       * TS OUTPUT:
       * (parameter) paragraph: {
       *     readonly __typename: "EntityQueueParagraph";
       * }
       */
    }

    if (paragraph && 'id' in paragraph) {
      console.log(paragraph);
      /**
       * TS OUTPUT:
       * (parameter) paragraph: never
       */
    }
  });
}

Min tanke var at etter .__typename-sjekken, er begge alternativer tilgjengelige. Men jeg kan bare bruke entitetskøen definert i type A. Orden ser ikke ut til å være årsaken.

Det samme gjelder for den andre betingelsen, hvor jeg ville forvente at TS utleder typen B fordi id-feltet bare er tilgjengelig der.

Håper du kan gi meg et hint eller litt videre lesning. Tusen takk! mvh

REDIGER
Etter å ha lagt til en ny nøkkel til typen As EntityQueueParagraph-skriving (la til foo: number), er TS i stand til å skille de to typene... dessverre ikke brukbart for min situasjon.

Svar #1

Tilsynelatende med en map, i stedet for forEach har du allerede bedre arv. Og å endre fra paragraphs?. til paragraphs && paragraphs. når du sjekker __typename løste problemet ditt.

type A = ReadonlyArray<
  | { readonly __typename: 'EmbedParagraph' }
  | { readonly __typename: 'EntityQueueParagraph' }
  | null
> | null;

type B = ReadonlyArray<
  | { readonly __typename: 'EmbedParagraph' }
  | {
      readonly __typename: 'EntityQueueParagraph';
      readonly id: string | null;
      readonly title: string | null;
    }
  | null
> | null;

function test(paragraphs: A | B) {
  paragraphs?.map((paragraph) => {
    if (paragraph && paragraph.__typename === 'EntityQueueParagraph') {
      console.log(paragraph);
    }

    if (paragraph && 'id' in paragraph) {
      console.log(paragraph);
    }
  });
}