Broken emit when `Infinity` or `‑Infinity` ends up in a type position
Bug Report
🔎 Search Terms
-
Infinity -
NaN - numeric
- literal
🕗 Version & Regression Information
- Tested in: TypeScript 4.1.5 and TypeScript 4.3.0‑dev
- I was unable to test this on prior versions because https://github.com/microsoft/TypeScript/pull/9407 was implemented in TypeScript 2.0.
💻 Code
// @declaration
// @showEmit
// @showEmittedFile: index.d.ts
// @filename: index.ts
export const PositiveInfinity: 1e1_000_000 = 1/0 as any;
export const NegativeInfinity: -1e1_000_000 = -1/0 as any;
⏯ Playground Link
🙁 Actual behavior
TypeScript emits Infinity and ‑Infinity in a type position, which are intentionally invalid according to https://github.com/microsoft/TypeScript/pull/9407#issuecomment-229721835:
// index.d.ts
export const PositiveInfinity: Infinity;
export const NegativeInfinity: -Infinity;
🙂 Expected behavior
The Infinity and ‑Infinity values are valid in a type position, so that the generated .d.ts file is valid.
Also, it’d be nice to support literal NaNs, which would allow for Number.isNaN to be typed as:
interface NumberConstructor {
isNaN(number: unknown): number is NaN;
}
Related issues
- https://github.com/microsoft/TypeScript/issues/28682
- https://github.com/microsoft/TypeScript/issues/31752
- https://github.com/microsoft/TypeScript/issues/32277
- https://github.com/microsoft/TypeScript/issues/56272
You're mixing a bug report and a feature request together in one. Fixing the bug would be to emit the type number instead of Infinity. Introducing an Infinity (and NaN) type is a feature request, for which you should provide a good reasoning in response to https://github.com/microsoft/TypeScript/pull/9407#issuecomment-229721835.
I for one have wanted Infinity/-Infinity as a special case for things that otherwise take BigInts e.g. ranges:
function* bigintRange(low: bigint, high: bigint | Infinity, step?: bigint=1n): Generator<bigint> {
for (let i = low; i < high; i += step) {
yield i;
}
}
@Jamesernator Just as a general advice: It tremendously helps when you explain your reasoning on why you want this, not just say "I want it for this". In your example you could just as well replace the Infinity with undefined. Having a dedicated Infinity type would not help you in this case, because Infinity would be a sub-type of number, so the union type number | Infinity would be simplified to number. Same as it happens with number | 5.
In your example you could just as well replace the Infinity with undefined. Having a dedicated Infinity type would not help you in this case, because Infinity would be a sub-type of number, so the union type number | Infinity would be simplified to number.
The example is bigint not number. BigInts don't contain an Infinity value, I think it's a lot more readable to use the explicit Infinity value rather than some arbitrary token as it already compares correctly with bigints (e.g. bigint < Infinity is always true, no coercion to Number happens).
@Jamesernator Just as a general advice: It tremendously helps when you explain your reasoning on why you want this, not just say "I want it for this". In your example you could just as well replace the
Infinitywithundefined. Having a dedicatedInfinitytype would not help you in this case, becauseInfinitywould be a sub-type ofnumber, so the union typenumber | Infinitywould be simplified tonumber. Same as it happens withnumber | 5.
More compelling explanations for why these types are needed can be found in https://github.com/microsoft/TypeScript/issues/28682 .
:wave: Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the repro in the issue body running against the nightly TypeScript.
Issue body code block by @ExE-Boss
:+1: Compiled
Emit:
export declare const PositiveInfinity: Infinity;
export declare const NegativeInfinity: -Infinity;
Historical Information
| Version | Reproduction Outputs |
|---|---|
| 4.9.3, 5.0.2, 5.1.3, 5.2.2, 5.3.2 |
:+1: Compiled
|