TypeScript: Built-in functions (e.g. isFinite) type guard and accepting null | undefined (strictNullChecks)

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:

  • isFinite should accept number | null | undefined rather than strictly number.
  • isFinite should act as a type guard.

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 😃

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 9
  • Comments: 22 (8 by maintainers)

Commits related to this issue

Most upvoted comments

As far as I can understand this issue, my recent troubles with this issue, the current implementation of TypeScript (4.5.4), and the specifications of ECMAScript on the matter, both typings are wrong and should look something more like:

isFinite:

/**
 * Determines whether a supplied number is finite.
 * @param number Any numeric value.
 */
- declare function isFinite(number: number): boolean;
+ declare function isFinite(number: unknown): boolean;
  1. Let num be ? ToNumber(number).
  2. If num is NaN, +∞𝔽, or -∞𝔽, return false.
  3. Otherwise, return true.

19.2.2 isFinite, ECMA-262

NumberConstructor.isFinite:

/**
 * Returns true if passed value is finite.
 * Unlike the global isFinite, Number.isFinite doesn't forcibly convert the parameter to a
 * number. Only finite values of the type number, result in true.
 * @param number A numeric value.
 */
- isFinite(number: unknown): boolean;
+ isFinite(number: unknown): number is number;
  1. If Type(number) is not Number, return false.
  2. If number is NaN, +∞𝔽, or -∞𝔽, return false.
  3. Otherwise, return true.

21.1.2.2 Number.isFinite, ECMA-262

this can definitely be improved. for example when doing:

function secondsSinceX(x: number | undefined): number {
  if (Number.isFinite(x)) {
    assert(x > 1)
...
  }
...
}

typescript warns me about the x in the assert that Object is possibly 'undefined'. but x cannot possibly be undefined in this case.

isFinite(null) actually returns true (null gets coerced to 0)

JavaScript (╯°□°)╯︵ ┻━┻

It’s probably best to not allow null, then?

isFinite(null) actually returns true (null gets coerced to 0)

It would also be useful if it returned a type predicate.

isFinite(number: number|string|null|undefined): number is number;