Skip to content

Infinity & NaN Type-level Support - #51741

Closed
graphemecluster (graphemecluster) wants to merge 4 commits into
microsoft:mainfrom
graphemecluster:infinity-nan
Closed

graphemecluster (graphemecluster) wants to merge 4 commits into
microsoft:mainfrom
graphemecluster:infinity-nan

Conversation

@graphemecluster

@graphemecluster graphemecluster (graphemecluster) commented Dec 4, 2022 •

Copy link
Copy Markdown
Contributor

Fix #15135
Fix #32277
Fix #42905


Related: #28682

@typescript-bot TypeScript Bot (typescript-bot) added the For Backlog Bug PRs that fix a backlog bug label Dec 4, 2022
@typescript-bot

Copy link
Copy Markdown
Contributor

The TypeScript team hasn't accepted the linked issue #15135. If you can get it accepted, this PR will have a better chance of being reviewed.

@graphemecluster

Copy link
Copy Markdown
Contributor Author

I don't think I can fix the linter though.

@sandersn

Copy link
Copy Markdown
Member

Wesley Wigham (@weswigham) do you remember the outcome of discussions when you experimented with this earlier? My memory is that we decided not to add these types but I don't remember the reason. I guess that the reason still holds, but it might not.

@sandersn

Copy link
Copy Markdown
Member

To help with PR housekeeping, I'd like to close this PR unless Wesley Wigham (@weswigham) wants to advocate for the feature again.

@graphemecluster
graphemecluster (graphemecluster) marked this pull request as draft March 11, 2023 05:46
@graphemecluster

Copy link
Copy Markdown
Contributor Author

I would make it a draft for the time being.

@weswigham Wesley Wigham (weswigham) left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally had NaN and Infinity types in early drafts of literal type PRs, so I'm biased, so I think this feature has a bit of value; however, as-is, this is a smidge incomplete. This adds the types and symbols, which is nice (and simplified our now-present syntactic NaN checks, which is a nice bonus), but is missing the falsy behavior for NaN which is the big sticking point in the whole thing. Once you correctly flag NaN as falsy, every if (!someNumber) in control flow needs to become 0 | NaN, and that's truly painful to deal with because of how toxic NaN is. And usually you don't even need to, since most people consider number to mean only finite numbers, and NaN and Infinity aren't even considered as options. Now, does this mean they may have silent bugs? Yes. Maybe. But generally, people don't really want to add isFinite checks everywhere.

IMO, I think the only way forward in that direction is with a new number base type that explicitly includes the non-finite types. So number today formally takes on the meaning of "finite numbers", and a hypothetical floating (or whatever it's called) is number | Infinity | -Infinity | NaN, so people can opt-in to the stricter checks. Now, that in turn has some DOM lib questions which'd need answering (are there any numbers that needs to become floating, and will that extra strictness break people, does there need to be a flag?).... it's a bit of a rabbithole for very minimal benefit, since, in practice, NaN and Infinity don't usually come up in well-formed code, which is generally the goal.

Also notable: You can actually acquire an Infinity type today already - type Infinity = 999999999999999999999999999999999999 does actually get you an Infinity type (because numbers overflow). The global Infinity is simply not typed that. This may void your warranty on declaration emit, however, since "literal types that print back as identifiers" is likely not something the emitter is pleased with, and both the builtin isFinite guard doesn't guard it and control flow doesn't produce it from expression operations, which limits its use.

Anyways. Thoughts. I personally like the idea, in theory, but in practice, it's a bigger can of worms than is worth considering for pretty much no benefit. If someone came forward with all those solved, maybe we'd consider it, but even then I can't make any guarantees.

Comment thread src/compiler/checker.ts
const requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String);
const isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules";

const InfinitySymbol = createSymbol(SymbolFlags.Property, "Infinity" as __String);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer to not capitalize these, since they're not classes (even if it makes them a bit less consistent with their symbol names, it's fine).

@graphemecluster

graphemecluster (graphemecluster) commented Mar 29, 2023 •

Copy link
Copy Markdown
Contributor Author

Wesley Wigham (@weswigham) Would something like #28682 be considered? (I don’t think I am capable of handling it though)

@smikitky

Copy link
Copy Markdown

I think the toxicity of NaN should be separated from the need for Infinity as a literal type.

since, in practice, NaN and Infinity don't usually come up in well-formed code

for pretty much no benefit

This may be true in most situations, but handling Infinity as a literal type is perfectly meaningful and critically important in some math-related codebases, especially after the introduction of bigint. Infinity is the only primitive that is guaranteed to be larger than any bigint (which is always "finite"), and many people are suffering from the lack of this support. See #32277

I personally consider it a bug that TypeScript still does not provide a way to handle a perfectly valid and well-defined member of number as a literal type. Infinity is a "number", not "not-a-number".

@sandersn

Copy link
Copy Markdown
Member

This has been stuck for a couple of years on the design questions raised by Wesley Wigham (@weswigham). That implies to me that this PR should be closed and we should wait on implementation until we have a design everyone is happy with.

@graphemecluster

Copy link
Copy Markdown
Contributor Author

Nathan Shively-Sanders (@sandersn)

a design everyone is happy with

This is literally impossible. Every coin has two sides. For every decision, there is always someone who is dissatisfied.


Anyway, IMO TypeScript should make their position clear and unambiguous, rather than not recognizing those types while condoning hacks like 1e888 all around at the same time (which is a loophole vulnerable to bugs like #42905 and more).

Honestly, yea, time proves that not dealing with NaN is the behaviour most people are comfortable with.
I do still think the types themselves should be defined, but this doesn’t mean that they need to be a part of the type system unless users explicitly reference them. I agree they are mostly impractical during inference, but on the other hand, they are useful in user-land types. I don’t think including the falsy behaviour is a prerequisite for these types to be defined given Wesley Wigham (@weswigham)’s concern on dealing with non-finite numbers.

Well, I respect your decision. Feel free to reopen or take over this PR in the future.

@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Nov 5, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

None yet

5 participants