TypeScript Version: 2.0.0
Code
// --strictNullChecks
interface IExample {
value?: number;
}
let example: IExample = {};
if (isFinite(example.value)) { // Accept possibly `undefined`
let a = example.value; // Narrow to `number`
}
Expected behavior:
number | null | undefined rather than strictly number.Actual behavior:
Won't compile because isFinite is not accepting undefined and is not a type guard.
Proposal:
Change:
declare function isFinite(number: number): boolean;
To:
declare function isFinite(number: number | null | undefined): number is number;
I'm pretty sure there are other functions that could use the same love.
I don't mind putting in some hours if this is an accepted direction to take. Let me know :)
Be sure to read contributing.md for instructions on how to make lib.d.ts changes
isFinite(null) actually returns true (null gets coerced to 0)
isFinite(null) actually returns true (null gets coerced to 0)
JavaScript (╯°□°)╯︵ ┻━┻
It's probably best to _not_ allow null, then?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite
isFinite('0') also returns true. Number.isFinite('0') returns false, but is only available in ES6 land.
Since these functions can take any type for input, I'd like to see the parameter type changed to any.
What are people passing a string to isFinite attempting to determine about that string?
For isFinite, I suppose the developer is trying to determine if the input can be coerced into a finite number.
For Number.isFinite, I am reading in an any and doing a runtime check to ensure the value is a finite number, so not NaN, Infinity, '0' or null.
any is the accurate representation of the spec. but we opted into making strict to catch cases more error cases, that otherwise would be masked by coercion, e.g. isFinite(getNumber) instead if isFinite(getNumber()). I suppose changing the type to number|string|null|undefined would be safer.
It would also be useful if it returned a type predicate.
isFinite(number: number|string|null|undefined): number is number;
@athasach it can't do that, because it coerces its argument. All isFinite (the global) tells you is if the coerced version of the argument parsed to a finite value; isFinite("30") is true but "30" is not a number
@RyanCavanaugh I should have specified Number.isFinite, which doesn’t coerce the value as far as I know.
Bumping this. According to the spec, Number.isFinite and similar Number do not throw, nor do they specify type constraints.
https://www.ecma-international.org/ecma-262/10.0/index.html#sec-number.isfinite
If Type(number) is not Number, return false.
If number is NaN, +∞, or -∞, return false.
Otherwise, return true.
That's it. Very simple. There are is no reason for this and similar functions to be constrained as such, since these constraints do not follow the spec itself. This isn't a huge deal as it's easy to extend the types, e.g.
interface NumberConstructor {
isFinite(v?: any): v is number
}
Most helpful comment
JavaScript (╯°□°)╯︵ ┻━┻
It's probably best to _not_ allow
null, then?