https://github.com/microsoft/TypeScript/issues/21199#issueco...
https://github.com/microsoft/TypeScript/issues/21199#issueco...
If isInteger was marked as a type guard, then you could write code like this:
function f(s: string | number) {
if (!Number.isInteger(s)) {
console.log(s.substring(0, 0));
}
}
which is clearly wrong.There's an open feature request for a new kind of "one-sided" type guards that don't cause narrowing when they return false.
const intSymbol = Symbol('integer')
type integer = number & {[intSymbol]: never}
const isInteger = (n: unknown): n is integer => Number.isInteger(n)
function f(s: string | number) {
if (isInteger(s)) {
const allowed = s.toExponential()
} else {
// s still string | number
}
}
With this you even get to define functions that must accept integers, which is kinda neat. if (typeof s === 'number' && Number.isInteger(s)) {What I was showing here is that this solution is simpler than yours and just as good. Rather than add a utility function and a faux primitive type, I just do the normal workaround for TypeScript not supporting this, which is to redundantly check that something is both a number and an integer.
The critical bit is that you need to define a new type for `integer`s distinct from `number`s to allow reusing the code in a way that doesn't break the type system on the negative path, as Ryan and I demonstrated.
If it's in terms of performance, that seems like moving the goalposts. I also wonder if it could be optimized away.
Next time I run into it I might use this:
if (Number.isInteger(s)) {
const allowed = (s as number).toExponential()
...and keep the isInteger check close enough that it's readable....or this:
if (Number.isInteger(s)) {
const n = s as number // should be optimized away by the compiler I thinkWhatever floats your boat, as you say.
Have a nice day.
interface NumberConstructor {
isInteger(n: unknown): n is number & { Symbol(): never }
}Currently: either string OR number
Possible: either string | number OR just number
Are you implying in your other comment (that HN won't let me reply to) that Typescript has an "OR" operator that is distinct from "|"? Can you link to documentation on that?
if isInteger(x) is true, x is definitely a `number`
if isInteger(x) is false, x is unknown/unaltered (it remains `typeof x`)
Current type guards can't express "yes versus maybe", so isInteger cannot be a type guard at all.