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

TypeScript BigInt support #2648

Open
ryan0x44 opened this issue Sep 6, 2024 · 0 comments
Open

TypeScript BigInt support #2648

ryan0x44 opened this issue Sep 6, 2024 · 0 comments

Comments

@ryan0x44
Copy link

ryan0x44 commented Sep 6, 2024

Currently 64-bit integers use the number type in generated TypeScript files, but should be bigint type instead.

Context (Input, Language)

Example JSON input:

{
  "example32": 9007199254740992,
  "example64": 9007199254740993
}

Example TypeScript output:

export interface Welcome {
    example32: number;
    example64: number;
}

This conversion can easily be verified at https://app.quicktype.io/?l=ts

When performing a JSON.parse from the above JSON into the above interface or its equivalent type, the example64 number would be 9007199254740992 (ending in 2) despite the JSON value being 9007199254740993 (ending in 3).

The correct TypeScript output should be:

export interface Welcome {
    example32: number;
    example64: bigint;
}

Description

I'm working on a system which sends large numbers between Go and TypeScript components via JSON.
The Go code which can 'marshal' a struct containing an int64 to JSON would produce the number as expected in JSON.

{
"example64":9007199254740993
}

This is because JSON and JSON Schema does not define precision of numbers (see Context for more on this).

Here's an example of some Go code (note the maximum signed integer value for 32-bit integers in Go is 2147483647):

package main

import (
	"encoding/json"
	"fmt"
)

type exampleStruct struct {
	Example32 int32 `json:"example32"`
	Example64 int64 `json:"example64"`
}

func main() {
	exampleObject := exampleStruct{
		Example32: 2147483647,
		Example64: 9007199254740993,
	}
	fmt.Printf("Object: %+v\n", exampleObject)
	exampleJson, err := json.Marshal(exampleObject)
	if err != nil {
		panic(err)
	}
	fmt.Printf("JSON: %s\n", string(exampleJson))
}

You can run the above Go code here: https://go.dev/play/p/yHYyqAxzUr3

Current Behaviour / Output

Currently the generated TypeScript code infers the number type, even when the number 9007199254740993 or larger would not be able to be parsed into then stringify'd back into the JSON file by the generated TypeScript type.

Proposed Behaviour / Output

Quicktype should detect the size of the number and use the bigint type instead.

Context

As outlined here, "The JSON Schema data model explicitly includes arbitrary-precision numbers."

The latest JSON Schema (2020-12) document here defines number: An arbitrary-precision, base-10 decimal number value, from the JSON "number" value.

MDN BigInt reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

For more context on how BigInt works in TypeScript see this TypeScript playground example (note it must be ES2020 or later) for the code below:

// extend BigInt with a toJSON method so that JSON.stringify works with bigint
(BigInt.prototype as any).toJSON = function () {
  // WARNING: may require "core-js/modules/esnext.json.raw-json" polyfill in your runtime
  return JSON.rawJSON(this.toString());
};

const maxSafeNumber : number = 9007199254740992;
const maxSafeNumberAsBigInt : bigint = BigInt(maxSafeNumber);

console.log("32-bit integer examples...")
type Int32User = {
  id: number
}
const okInt32User : Int32User = {
  id: maxSafeNumber
}
console.log("okInt32User: " + JSON.stringify(okInt32User))
const notOkInt32User : Int32User = {
  id: maxSafeNumber+1
}
console.log("notOkInt32User: " + JSON.stringify(notOkInt32User))

console.log("64-bit integer examples...")
type Int64User = {
  id: bigint
}
const okInt64User : Int64User = {
  id: maxSafeNumberAsBigInt
}
console.log("okInt64User: " + JSON.stringify(okInt64User))
const stillOkInt64User : Int64User = {
  id: maxSafeNumberAsBigInt+1n
}
console.log("stillOkInt64User: " + JSON.stringify(stillOkInt64User))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant