Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bigint literal type -0n exists, and is not handled consistently #60466

Open
That-Guy977 opened this issue Nov 10, 2024 · 4 comments
Open

Bigint literal type -0n exists, and is not handled consistently #60466

That-Guy977 opened this issue Nov 10, 2024 · 4 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@That-Guy977
Copy link

That-Guy977 commented Nov 10, 2024

πŸ”Ž Search Terms

bigint negative zero template

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about bigint

⏯ Playground Link

https://www.typescriptlang.org/play/?target=99&ts=5.6.3#code/C4TwDgpgBACg9gZwFoQE5ygXigBgHYDcAUKJFAHIQDmK6WUAtPgVK2+x5wPRdQD8AQiI82APT5EAxnDwJgUMAC8AXLES0M2JoSky5UPCorUN9ZkRLhoAZWCpKNNJqgADACQBvbQF8Xnf1AigsK8rOKWZLaoAEIAllQAknjy2O4eeACuALYARmi+urLyAB6qUXGJyfQAREzVLAEcQUIR0DAAhqgIEBVJwAA8ACpQEMXAEHgAJgiunjnxscm+AHz0w6PjUzNpiwBmaFB9I2MT01DzVIvAvvyHVap4EABuaK1qCLHAsS8A8o-0HS6PXifX6AHIAIxg5YhMQSUjQBztL6-f7YQHdXrJcEMKEwkRheFWd6fb4QUzozqYkHYsE4aGwwlvJEo8lOAFU4GVAZgpjQtjNRlQcRAA

πŸ’» Code

type PosZero = 0n;
type NegZero = -0n;                     // ?!
//   ^? - type NegZero = 0n
const pz: PosZero = -0n;
const nz: NegZero = 0n;

type StrNegZero = `${-0n}`              // ?!
//   ^? - type StrNegZero = "0"
type StrBigInt = `${number}`
const x: StrBigInt = "-0";              // ?!

type ParseBigInt<T extends `${bigint}`> = T extends `${infer Int extends bigint}` ? Int : never
type PositiveOne = ParseBigInt<'1'>
//   ^? - type PositiveOne = 1n
type NegativeOne = ParseBigInt<'-1'>
//   ^? - type NegativeOne = -1n
type PositiveZero = ParseBigInt<'0'>
//   ^? - type PositiveZero = 0n
type NegativeZero = ParseBigInt<'-0'>   // ?!
//   ^? - type NegativeZero = bigint

πŸ™ Actual behavior

-0n is a valid and evalutates to 0n, and "-0" matches `${bigint}`, but `${-0n}` evalutates to "0", and "-0" is not successfully inferred as 0n

πŸ™‚ Expected behavior

-0n should either not exist, or it should be handled consistently with other bigint literals.
Either:

  • -0n should fail, and "-0" should not match `${bigint}`, because -0n is not a valid bigint value, and thus no such bigint stringifies to -0.
  • "-0" should be inferred to contain 0n/-0n, because -0n is valid syntax that evalutates to 0n.

Additional information about the issue

Credit to mkantor and sinclair in the TypeScript Community for extra examples.

@That-Guy977 That-Guy977 changed the title Bigint -0n exists, and is not handled consistently Bigint literal type -0n exists, and is not handled consistently Nov 10, 2024
@jcalz
Copy link
Contributor

jcalz commented Nov 10, 2024

Is this really specific to bigint? I think the same thing happens with number.

Is this really specific to -0? I think the same thing happens with any numeric literal where you are writing it in a form that differs from how that number gets serialized as a string (think 1.0 instead of 1, or 1e2 instead of 100).

The difference between 0 and -0 as numbers can almost always be completely ignored in JavaScript and therefore in TypeScript (it's hard to test for it; maybe you can divide by it and see which flavor of Infinity you get?). And there is no difference at all between 0n and -0n; the latter is just another way to write the former, like 0xFn is another way to write 15n.

I'm not seeing a bug here. The behavior where TS can only infer numbers from "round-trippable" strings is documented in the release notes and #48094, so one should expect ParseBigInt<-0> to be bigint.

@That-Guy977
Copy link
Author

Is this really specific to bigint? I think the same thing happens with number.

-0 is an actual existant value for number, though true that it's stringified as 0 as well.
Also just checked and TS does serialize -0 as 0, which I was not expecting

Is this really specific to -0? I think the same thing happens with any numeric literal where you are writing it in a form that differs from how that number gets serialized as a string (think 1.0 instead of 1, or 1e2 instead of 100).

I'm not seeing a bug here. The behavior where TS can only infer numbers from "round-trippable" strings is documented in the release notes and #48094, so one should expect ParseBigInt<-0> to be bigint.

I was not aware of these for the template types, thanks for the links.

But so far, I still think that -0n should not be a valid bigint literal type, since it's not an existant value, unlike -0. Is there a reason for that to specifically exist as a literal type?

@jcalz
Copy link
Contributor

jcalz commented Nov 10, 2024

The type -0n is the same type as 0n, it’s just another way to write it. I don’t see why TS should error if you write -0n, unless it should also error if you write 0xFn.

@RyanCavanaugh
Copy link
Member

I don't understand what the bug is supposed to be here either. -0n === 0n and the examples reflect that, right? I'm also unsold on what banning -0n would accomplish except to specifically address people who have gone looking for this trouble and successfully found it.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

3 participants