Open smikitky opened 5 years ago
Also, to state the obvious in favour of this, typeof Infinity = "number"
, not some odd object.
Quizzically, Infinity
has some odd type conversions internally that may be at the heart of this:
type numberNames = {0: "zero", 1: "one", Infinity: "inf"};
type numberTypes = keyof numberNames;
// These are fine:
var zero:numberTypes = 0;
var one:numberTypes = 1;
// This is an expected error:
var two:numberTypes = 2;
/* ERROR
var two: 0 | 1 | "Infinity"
Type '2' is not assignable to type '0 | 1 | "Infinity"'.
*/
// This is an unexpected error:
var inf:numberTypes = Infinity;
/* ERROR
var inf: 0 | 1 | "Infinity"
Type 'number' is not assignable to type '0 | 1 | "Infinity"'.
*/
Here, Infinity
is treated as a string
... not a number
, unlike the other number keys.
So, Infinity
might be treated just like any other simple string key here, at least.
const Inf = 999e308;
type Infinity = 999e999999; //Just for fun, it's still the same as `Inf`
//We use `Inf` instead of `Infinity`
type numberNames = {0: "zero", 1: "one", [Inf]: "inf"};
type numberTypes = keyof numberNames;
// These are fine:
var zero:numberTypes = 0;
var one:numberTypes = 1;
// This is an expected error:
var two:numberTypes = 2;
/* ERROR
var two: 0 | 1 | "Infinity"
Type '2' is not assignable to type '0 | 1 | "Infinity"'.
*/
// OK!
var inf:numberTypes = Infinity as Infinity;
I have a very similar use case and was surprised that this doesn't work.
Also prevents you from making Infinity a mandatory key in a Record
:
export type ImageSrcSet = Record<number, string> & { [Infinity]: string };
I'd expect that to resolve to a numeric dictionary where all keys are optional except for Infinity
. Instead, it triggers TS1170: a computed property name must be a literal type.
I agree it makes sense to add Infinity
and -Infinity
- these could be treated as top/bottom elements (pity we don't have orderings in types). And as with the reference from #44408, some operations have special behaviour for Infinity
, so it would be handy to be able to describe this behaviour in the types.
Additional silly (?) use case:
Consider a roleplaying game where players roll a dice against an unconstrained difficulty number.
You'd like a type that includes the possible die results plus an 'auto-succeed' value for peculiar circumstances, e.g.
type D6 = 1|2|3|4|5|6|Infinity
Another use case is to have richer type/value checking. I have this module where this feature would certainly be helpful for any library-API user (usually, only myself, haha)
I also ran into this when implementing unbounded ranges, hoping that bigint | Infinity
would be possible.
I have been waiting for this for over 4 years.
Unless I'm missing something, (-)Infinity
is the only distinct primitive value that TypeScript cannot correctly treat in a literal type context. Aside from NaN
(which is not "distinct" in the first place), all primitive values, including bigints and symbols, can be correctly handled as a literal type. I personally think this is more of a defect than a feature request.
Infinity
is the only member of the number
type that is guaranteed to be larger than any bigint
, which is important in some practical scenarios. Infinity
is not some "error value" that arises from some unexpected calculation result, but is a fully-fledged constant whose behavior is strictly and rationally defined in the world of numerical computation in JavaScript.
My usecase for Infinity is a "flatten" utility accepting a depth of number including Infinity. It would be nice to overload for the case of depth: Infinity
. Creating a separate function or signature for this case would be expanding the api only to appease typescript
As long as Infinity exists in JavaScript, I think people will find reasonable use cases for it from time to time, and TypeScript is limiting its utility for no good reason.
Today I wanted to write a function like
expiry(): Date | Infinity
Please accept
Infinity
and-Infinity
as valid number literal types.Currently, This causes a compile error,
'Infinity' refers to a value, but is being used as a type here. (2749)
.I understand this was once rejected as part of #15135 and #15356, and the given reasons were: 1) difficult to implement, and 2) lacks a compelling use case.
However, while I understand why
NaN
as a literal type is tricky to implement,NaN
andInfinity
are not the same. And I have a clear use case forInfinity
as a meaningful literal type, as shown above.Infinity is not tricky to compare
Unlike notorious
NaN
or-0
,Infinity
works just like an ordinary numeric constant as far as equality is concerned. We don't need a special function likeisNaN()
orObject.is()
. Ever since the ES5/IE6 era, there has been nothing counter-intuitive:Most importantly,
Infinity === Infinity
is true (whileNaN === NaN
is false). Unless I'm missing something, predictable equality is all that's required to safely useInfinity
as a literal type, right? Even though the design note (#15356) says "there is more than one NaN, Infinity, etc", you can think ofInfinity
in JavaScript as "just a fixed number" which happens to be larger thanNumber.MAX_VALUE
.My use case
My library deals with unbounded (aka infinite) integer ranges, and I have been using
Infinity
and-Infinity
without any issue to denote what they literally mean, infinity in the mathematical sense. I have instructed my users to use these interesting constants, too. Recently I started to extend my library to supportbigint
in addition tonumber
, and ran into this problem.You may ask "Why don't you just use string
'Infinity'
orSymbol('unbounded')
", butInfinity
is a predefined and predictable constant, and it can be directly compared with any bigint (e.g.,10n ** 1000n < Infinity
istrue
). See how simple the implementation ofisValid
can be in the first example.PS: Looks like there is a hacky workaround (#31752), but I'd like to see the official support.