TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Broken emit when `Infinity` or `‑Infinity` ends up in a type position

Open ExE-Boss opened this issue 4 years ago • 6 comments

Bug Report

🔎 Search Terms

  • Infinity
  • NaN
  • numeric
  • literal

🕗 Version & Regression Information

💻 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

Workbench Repro

🙁 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

ExE-Boss avatar Feb 21 '21 12:02 ExE-Boss

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.

MartinJohns avatar Feb 21 '21 12:02 MartinJohns

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 avatar Feb 22 '21 07:02 Jamesernator

@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.

MartinJohns avatar Feb 22 '21 08:02 MartinJohns

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 avatar Feb 22 '21 08:02 Jamesernator

@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.

More compelling explanations for why these types are needed can be found in https://github.com/microsoft/TypeScript/issues/28682 .

ca-d avatar Apr 23 '21 12:04 ca-d

: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
Emit:

export declare const PositiveInfinity: Infinity;
export declare const NegativeInfinity: -Infinity;

typescript-bot avatar Dec 04 '23 08:12 typescript-bot