You can try my code in a typescript playground:
export interface A {
label: string;
kind: "A";
}
export interface B {
label: `Baz ${number}`;
kind: "B";
}
// in another file...
type SubUnion = A | B;
const createObj = (): SubUnion[] => {
const x = true;
const n1 = 3;
const n2 = 5;
const result: SubUnion[] = [
{ label: "Foo", kind: "A" },
{ label: "Bar", kind: "A" },
{
/*
Type '{ label: string; kind: "B"; }' is not assignable to type 'SubUnion'.
Types of property 'kind' are incompatible.
Type '"B"' is not assignable to type '"A"'.(2322)
*/
label: `Baz ${x ? n1 : n2}`,
kind: "B",
},
];
return result;
};
I don't understand the last two lines of that error message. Why is it saying Type '"B"' is not assignable to type '"A"'?
Fortunately, I think I understand the first line: it's saying that label: `Baz ${x ? n1 : n2}`, is a string type, but B needs a Baz ${number} type. I've found ways to fix this, but I'm not sure if any are "the right way" to do it:
-
const result: SubUnion[] = [ { label: "Foo", kind: "A" }, { label: "Bar", kind: "A" }, { label: `Baz ${x ? n1 : n2}`, kind: "B", }, ] as const; -
{ label: `Baz ${x ? n1 : n2}`, kind: "B", } satisfies B, -
{ label: `Baz ${x ? n1 : n2}`, kind: "B", } as const, -
{ label: `Baz ${x ? n1 : n2}` satisfies `Baz ${number}`, kind: "B", }, -
{ label: `Baz ${x ? n1 : n2}` as const, kind: "B", },
I can say with some confidence that as const is not the best way to do this: it lets you use literals that don't match the type on the left-hand side of the assignment. I don't know if that means satisfies is the right way to do this, but it does seem better.
In summary: Why is this error message so confusing and is there a better way to fix the error?