richbai90
richbai90

Reputation: 5204

Object destructuring prevents typescript discrimination

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

Answers (1)

Mikhail Burshteyn
Mikhail Burshteyn

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 cases 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

Related Questions