I want to write a type guard function which compares the first given value with the second expected value and infers the type of the first value to be the same as the type of the second value. So regarding to type narrowing I want the type guard to do the same as the strict equal operator in this code:
class Product { public constructor(public id: number) {}; }
class NiceProduct extends Product { public niceFactor = 10; }
class UglyProduct extends Product { public uglyFactor = 20; }
function test(a: NiceProduct | UglyProduct) {
const b = new NiceProduct(2);
if (a === b) {
// a is now a NiceProduct
} else {
// a is still NiceProduct | UglyProduct
}
}
I can’t simply use a strict equal check because I have to compare product IDs instead, so two instances of the same product class with the same ID are treated equal. My naive approach is this:
function isSameProduct<T extends Product>(a: Product, b: T): a is T {
return a.constructor === b.constructor && a.id === b.id;
}
The problem is, this type guard messes up the type inferrence in the else block:
function test(a: NiceProduct | UglyProduct) {
const b = new NiceProduct(2);
if (isSameProduct(a, b)) {
// a is now a NiceProduct (like b) which is correct
} else {
// a is now just an UglyProduct but I need it to be the original
// type (NiceProduct | UglyProdyuct) because it could also be a
// NiceProduct with a different ID.
}
}
Is there a way to write a type guard function which behaves like the strict equal check, so it only affects type inference in the true-condition and not in the false-condition?