Fiddling around with a union of arrays which contains objects. Expected that TS is able to guard the correct type but I guess I am missing smth here:
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
*/
}
});
}
My thought was, that after the .__typename
check, there are both options available. But I am only able to use the entity queue defined in type A
. Order does not seem to be the reason.
Same goes for the 2nd condition where I would expect that TS infers type B
because the id
field is only available there.
Hope you can give me a hint or a further read. Thanks a lot! bw
EDIT
After adding a new key to type A
s EntityQueueParagraph
typing (added foo: number
), TS is able to distinguish the two types... unfortunately not usable for my situation.
CodePudding user response:
Apparently with a map
, instead of forEach
you already have better inheritance. And changing from paragraphs?.
to paragraphs && paragraphs.
when checking the __typename
fixed your issue.
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);
}
});
}