Skip to content

Assertion functions cannot be used to narrow discriminated union types #37241

Description

Recently I tried to get creative with an assert function, but ran into a shortcoming. I think I understand why this is the behavior, but it would be nice if it wasn't the case.

TypeScript Version: 3.9.0-dev.20200304

Search Terms: assertion assert function discriminated union narrowing

Code

interface Cat {
  type: 'cat';
  canMeow: true;
}

interface Dog {
  type: 'dog';
  canBark: true;
}

type Animal = Cat | Dog;

function assertEqual<T>(value: any, type: T): asserts value is T {
  if (value !== type) {
    throw new Error('Not equal!');
  }
}

const animal = { type: 'cat', canMeow: true } as Animal;
assertEqual(animal.type, 'cat' as const);

// Error
animal.type; // "cat"
animal.canMeow; // Property 'canMeow' does not exist on type 'Dog'

// Works
if (animal.type !== 'cat') {
  throw new Error();
}
animal.canMeow; // true

Expected behavior:
Calling assertEqual(animal.type, 'cat') would infer animal as a Cat.

Actual behavior:
Only animal.type by itself is inferred; the type narrow does not "propagate" up to the union type.

Playground Link: Provided

Related Issues: #11787 (most closely related, but that's for type guards, not the new assertion functions), #34596

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions