better-typescript-lib
better-typescript-lib copied to clipboard
Type guard on `Number.isInteger` is too strong
I was reading the discussion at https://github.com/microsoft/TypeScript/issues/15048 and noticed that the definition of Number.isInteger from this library has the mentioned type guard, number is number.
To summarize the problem: When Number.isInteger returns false, the passed value may still be a number (just not an integer).
Unfortunately as that discussion shows there is currently no good way to represent this kind of 'weak type guard' in TypeScript, although https://github.com/microsoft/TypeScript/issues/15048#issuecomment-1174371299 does present an interesting workaround.
Adapted from that comment, you could do something like the following:
declare const container: unique symbol;
type SubtypeOf<T> = T & { [container]: T };
interface NumberConstructor {
isInteger<T>(number: T): number is number & SubtypeOf<T>;
}
function test(n: unknown) {
if (typeof n === "string" || typeof n === "number") {
const a = n; // string | number
if (Number.isInteger(n)) {
const b: number = n; // number & { [container]: string | number }
} else {
const e = n; // string | number
}
}
}
Although the truthy branch has an awkward type for n, the assignment to b is valid (and the falsy branch maintains the unconstrained type).
I don't know what the best solution is here - remove the type guard, apply the workaround, or leave the type guard in place. The current type guard is technically unsafe though.