Reputation: 5204
I've been playing with typescript discrimination using tagged union types and I've run into something odd. If I switch on the actual object property everything works as expected. But if I use destructuring, typescript reports an error. I assume it has to do with how destructuring actually works when its compiled, but I don't know for certain. You can see this sample code on the playground
interface Foo {
discriminate: 'FOO';
details: string;
}
interface Bar {
discriminate: 'BAR';
numbers: number;
}
type FooOrBar = Foo|Bar;
const foo : Foo = {
discriminate: 'FOO',
details: 'Blah Blah Blah'
}
const breakTaggedUnionWithRest = ({discriminate, ...fooBar} : FooOrBar) => {
switch(discriminate) {
case 'FOO':
console.log(fooBar.details);
break;
}
}
interface Foo2 {
discriminate: 'FOO2';
details: string;
}
interface Bar2 {
discriminate: 'BAR2';
details: number;
}
type FooOrBar2 = Foo2|Bar2;
const breakTaggedUnionWithoutRest = ({discriminate, details} : FooOrBar2) => {
switch(discriminate) {
case 'FOO2' : return details.toLowerCase();
}
}
const workingExample = (fooOrBar: FooOrBar) => {
switch(fooOrBar.discriminate) {
case 'FOO': return fooOrBar.details;
}
}
const workingExample2 = (fooOrBar: FooOrBar2) => {
switch(fooOrBar.discriminate) {
case 'FOO2': return fooOrBar.details.toString;
}
}
Upvotes: 4
Views: 527
Reputation: 5002
If you don't destructure, the switch
-case
on the discriminator property allows TypeScript to narrow the type of the whole fooOrBar
object and correctly deduce types of other properties on that object. This is because TypeScript understands that you're trying to discriminate by a property of the object.
With destructuring, however, discriminate
and other variables (fooBar
in your first example and details
in the second) become not related to each other. As a result, in the case
s TypeScript doesn't deduce that the type of another variable may be narrowed, because the variable under switch
and the variable you're trying to access are not related in any way at that point.
Upvotes: 3