Skip to content

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

Closed
@oleg-codaio

Description

@oleg-codaio

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

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions