How narrow union of object types when the discriminating field has overlap?

Viewed 41

I have a type below:

type Animal = {
  kind: 'cat';
  params: string;
} | {
  kind: 'dog';
  params: number[];
} | {
  kind: string;
  params: Record<string, string>
}

When I'm trying to narrowing down the Animal type using switch, it couldn't narrow down to specific object type.

switch (animal.kind) {
  case 'cat':
    console.log(animal.params.toUpper())  // Error: animal.params is a type of `string | Record<string, string>`
    break;
  case 'dog':
    console.log(animal.params.length)
    break;
  default:
    console.log("animal is an object");
}

But this is not working. In the first case it thinks params is string | Record<string, string>.

I understand it's because string and "cat" has overlap, but how can I make this narrowing happen?

1 Answers

As @jcalz mentioned in the comments of the question, It seems that this is a typescript Design Limitation.

Base on the comment here, Typescript needs to do something like negated types (string - cat - ...) which Typescript is not designed desecrate unions like that.

Related