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 As 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);
}
});
}
