Closed
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