TypeScript BigInt support
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))