Closed
Description
Suggestion
π Search Terms
disallow NaN
comparing with NaN
disallow comparing NaN
β Viability Checklist
My suggestion meets these guidelines:
- [?] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- β This wouldn't change the runtime behavior of existing JavaScript code
- β This could be implemented without emitting different JS based on the types of the expressions
- β This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- β This feature would agree with the rest of TypeScript's Design Goals.
β Suggestion
Similar to #45978 . So the error should be something like The condition will always return 'false' since NaN !== NaN. Use Number.isNaN.
π Motivating Example
function setReputation (n: number)
{
// ! here is the bug:
if (n === NaN) throw new Error('setReputation:: Impossible reputation')
// update the record in a remote DB
}
const foundGolems = 0
const killedGolems = 0
setReputation(killedGolems / foundGolems * 100)
// 0/0 is NaN
or what has actually happened to me:
export function clamp ( // @license CC0
n: number,
min: number|bigint,
max: number|bigint,
): typeof n
export function clamp (
n: bigint,
min: number|bigint,
max: number|bigint,
): typeof n
export function clamp (
n: number|bigint,
min: number|bigint,
max: number|bigint,
): typeof n
{
// +null === 0
// +'' === 0
// +undefined === NaN
const nFixed = typeof n === 'bigint' ? n : (
// @ts-ignore
'' === n || n === null || typeof n === 'symbol'
? NaN : +n
)
const minFixed = typeof min === 'bigint' ? min : (
// @ts-ignore
'' === min || min === null || typeof min === 'symbol'
? NaN : +min
)
const maxFixed = typeof max === 'bigint' ? max : (
// @ts-ignore
'' === max || max === null || typeof max === 'symbol'
? NaN : +max
)
if (nFixed === NaN)
{
const ret = nFixed
//const ret = min == max ? (typeof min === 'bigint' ? +min.toString() : min) : nFixed
console.warn(
'clamp(n=%O, min=%O, max=%O):: n === NaN; returning %O',
n, min, max, ret,
)
return ret
}
let ret: typeof n
if (
minFixed === NaN
&&
maxFixed === NaN
)
{
ret = nFixed
console.warn(
'clamp(n=%O, min=%O, max=%O):: min === NaN && max === NaN; returning `n` (%O)',
n, min, max, ret,
)
}
else if (maxFixed < minFixed)
{
// throw new RangeError
//ret = maxFixed // similar to torch.clamp
ret = minFixed // because arguments are specified in the left-to-right *order*.
//ret = nFixed < maxFixed ? maxFixed : (nFixed > minFixed ? minFixed : nFixed)
/*console.warn(
'clamp(n=%O, min=%O, max=%O):: max<min; returning `min` (%O)',
n, min, max, ret
)*/
}
else
{
ret = nFixed < minFixed ? minFixed : (nFixed > maxFixed ? maxFixed : nFixed)
}
if (typeof n === 'bigint')
{
return typeof ret === 'bigint' ? ret : BigInt(Math.floor(ret))
}
if (typeof ret === 'bigint')
{
return +ret.toString()
}
return ret
}
π» Use Cases
Since NaN is very rare, a programmer could forget to use Number.isNaN(variable)
, and accidentally use ===
.
Or a programmer could have never even learned this, and just applies knowledge from other langs where NaN === NaN.