Der Primitive-Typ bigint ist TypeScripts Antwort auf eine alte JavaScript-Schwäche: number ist ein IEEE-754-Double und kann Ganzzahlen nur bis 2^53 - 1 exakt darstellen. Darüber kippt die Präzision lautlos um — 9007199254740993 wird zu 9007199254740992. bigint löst das mit beliebig großer Präzision und einer eigenen Literal-Syntax (100n). Der Preis: ein Pflicht-target: es2020 in der tsconfig.json, ein striktes Mischverbot mit number und ein paar überraschende Eigenheiten wie nicht-JSON-serialisierbare Werte. Dieser Artikel zeigt, wann du bigint brauchst, wie der Compiler ihn behandelt und welche Fallen warten.
Wozu bigint?
JavaScripts number ist ein 64-bit-Double nach IEEE 754. Das reicht für die meisten Berechnungen — bis du eine Integer brauchst, die größer ist als Number.MAX_SAFE_INTEGER (2^53 - 1, also 9007199254740991). Ab diesem Punkt verliert number lautlos Genauigkeit:
const max = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(max + 1); // 9007199254740992
console.log(max + 2); // 9007199254740992 — gleiche Zahl!
console.log(max + 3); // 9007199254740994 — Sprung um 2
console.log(9007199254740993 === 9007199254740992); // true9007199254740992
9007199254740992
9007199254740994
truebigint ist eine arbitrary-precision integer: beliebig viele Stellen, ohne Genauigkeitsverlust. Eingeführt wurde der Typ mit TypeScript 3.2 und ist heute in allen modernen Engines verfügbar.
const big: bigint = 9007199254740993n;
console.log(big); // 9007199254740993n
console.log(big + 1n); // 9007199254740994n
console.log(big * big); // 81129638414606735407491456n9007199254740993n
9007199254740994n
81129638414606735407491456nbigint-Literale
bigint-Literale sind normale Ganzzahl-Literale mit angehängtem n. Die üblichen Zahlensysteme funktionieren alle:
const dezimal: bigint = 100n;
const hex: bigint = 0xFFn; // 255n
const oktal: bigint = 0o744n; // 484n
const binaer: bigint = 0b1010n; // 10n
const negativ: bigint = -42n;
// Compile-Fehler: bigint kann keine Nachkommastellen darstellen
const falsch: bigint = 3.14n;
// ~~~~~ A bigint literal must be an integer.Ein Float-bigint existiert nicht — der ganze Sinn des Typs ist, dass es Ganzzahlen sind. Wer Kommazahlen mit hoher Präzision braucht, greift zu einer Library wie decimal.js.
target-Anforderung in der tsconfig.json
bigint ist Sprachfeature von ES2020. Wer ein älteres target setzt, bekommt vom Compiler einen klaren Hinweis:
// tsconfig.json: "target": "es2019"
const big = 100n;
// ~~~~ BigInt literals are not available when targeting
// lower than ES2020.Korrekte Mindest-Konfiguration:
{
"compilerOptions": {
"target": "es2020",
"lib": ["es2020", "dom"],
"strict": true
}
}Grund: bigint hat eigene Operator-Semantik (+, *, / etc.), die sich nicht trivial in älteres JavaScript downlevern lässt. Die Engine muss die Arithmetik nativ kennen.
Konvertierung zwischen bigint und number
Mit der globalen BigInt(...)-Funktion (ohne new) erzeugst du bigint-Werte aus number, String oder Boolean:
const ausZahl: bigint = BigInt(100); // 100n
const ausString: bigint = BigInt("9999999999999999999"); // beliebig groß
const ausHex: bigint = BigInt("0xff"); // 255n
// Rückweg: explizit Number(...)
const klein: bigint = 100n;
const num: number = Number(klein); // 100
// Präzisionsverlust beim Rückweg, wenn der Wert zu groß ist
const riesig: bigint = 9007199254740993n;
console.log(Number(riesig)); // 9007199254740992 — Stelle verloren9007199254740992Wichtig: BigInt(0.5) ist ein Laufzeitfehler (RangeError). Floats lassen sich nicht in bigint konvertieren, weil das per Definition Information vernichten würde.
Arithmetik mit bigint
Alle üblichen Operatoren funktionieren — und das Ergebnis ist immer ein bigint:
console.log(10n + 3n); // 13n
console.log(10n - 3n); // 7n
console.log(10n * 3n); // 30n
console.log(10n / 3n); // 3n — Integer-Division, abgeschnitten!
console.log(10n % 3n); // 1n
console.log(2n ** 64n); // 18446744073709551616n13n
7n
30n
3n
1n
18446744073709551616nDie Division ist der größte Stolperstein: 5n / 2n ergibt 2n, nicht 2.5n. bigint kennt keine Nachkommastellen, also schneidet / Richtung Null ab. Wer Rest braucht, kombiniert mit %.
Mischverbot mit number
Hier ist TypeScript besonders streng — und JavaScript zur Laufzeit ebenfalls. Du darfst bigint und number nicht in einer Arithmetik-Operation mischen:
const a: bigint = 100n;
const b: number = 1;
const x = a + b;
// ~~~~~ Operator '+' cannot be applied to types
// 'bigint' and 'number'.
// Auch zur Laufzeit ein TypeError:
// "Cannot mix BigInt and other types, use explicit conversions"
// Korrekt: explizit konvertieren
const y = a + BigInt(b); // 101n
const z = Number(a) + b; // 101 (mit Präzisionsrisiko bei großen a)Das ist eine bewusste Design-Entscheidung. Stille Konvertierung würde entweder Genauigkeit kosten (number-Seite) oder den Sinn von bigint untergraben.
Vergleiche zwischen bigint und number
Bei reinen Vergleichsoperatoren ist die Sprache toleranter, weil hier keine Genauigkeit verlorengeht:
console.log(100n < 101); // true
console.log(100n > 99); // true
console.log(100n <= 100); // true
// Loose Equality: konvertiert vor dem Vergleich
console.log(100n == 100); // true
// Strict Equality: Typ muss übereinstimmen
console.log(100n === 100); // false — bigint vs number
console.log(100n === 100n); // truetrue
true
true
true
false
trueFaustregel: relationale Operatoren (<, >, <=, >=, ==) dürfen mischen, === nicht. In striktem Code arbeitest du ohnehin immer mit === und konvertierst vorher explizit.
Wann bigint, wann number?
bigint ist ein Spezialwerkzeug, kein Default. Konkret sinnvoll:
- Kryptografie: Schlüssel, Modulo-Operationen, RSA-Berechnungen — alles weit jenseits von
2^53. - Datenbank-IDs: PostgreSQL
bigint(64-bit signed), Twitter-Snowflake-IDs, Discord-Snowflakes. Wer solche IDs alsnumberdeserialisiert, riskiert kaputte Werte bei großen Konten. - Timestamps in Nanosekunden:
process.hrtime.bigint()in Node.js liefert direkt einen bigint, weil Mikrosekunden-Tracking sonst überläuft. - Finance mit Cents als Integer: Beträge in der kleinsten Währungseinheit speichern und erst beim Anzeigen formatieren — bigint vermeidet Float-Drift komplett.
- Bit-Manipulation auf 64-bit-Werten:
&,|,^,<<,>>funktionieren mit bigint, ohne dass der 32-bit-Cap zuschlägt.
Für alles andere — Counter, Indexe, Maße, Prozente, Pixel — bleibt number die richtige Wahl. bigint hat einen messbaren Performance-Nachteil, weil die Werte nicht in einem CPU-Register liegen.
Interessantes
JSON.stringify mit bigint wirft TypeError.
Ein nackter Aufruf wie JSON.stringify({ id: 100n }) bricht mit TypeError: Do not know how to serialize a BigInt ab. Workaround: einen Replacer übergeben, der bigint zu String wandelt — oder direkt am Layer-Übergang konvertieren. Viele HTTP-APIs liefern bigint-Werte deshalb als JSON-String zurück, nicht als Zahl.
BigInt(0.5) wirft RangeError.
Floats lassen sich nicht in bigint konvertieren. BigInt(0.5), BigInt(NaN) und BigInt(Infinity) sind alle Laufzeitfehler. Wer aus einer number-Rechnung einen bigint braucht, muss vorher mit Math.trunc oder Math.floor auf eine Ganzzahl runden.
Performance: bigint ist deutlich langsamer als number.
Operationen auf bigint laufen über Heap-allokierte Objekte mit variabler Länge, nicht in CPU-Registern. Für Hot-Loop-Berechnungen mit Werten unter 2^53 ist number oft eine Größenordnung schneller. Benchmarke, bevor du bigint flächendeckend einsetzt.
bigint kennt kein Infinity und kein NaN.
Diese Werte gehören zu IEEE-754. bigint ist eine reine Integer-Welt: jeder gültige bigint ist eine endliche Ganzzahl. Division durch 0n wirft daher RangeError: Division by zero — statt Infinity zurückzugeben wie bei number.
Division schneidet Richtung Null ab.
5n / 2n ergibt 2n, nicht 2.5n und nicht 3n. Genauso wie in C oder Go: Integer-Division, Rest geht verloren. Wer den Rest braucht, kombiniert mit %; wer Kommazahlen will, muss vorher zu number konvertieren — mit allen Präzisionsrisiken.
TypeScript 5.0+ und isolatedModules.
Im isolatedModules-Modus (Standard bei Bundlern wie esbuild, swc, Vite) prüft TypeScript jede Datei isoliert. bigint-Literale funktionieren auch hier ohne Sonderbehandlung, weil sie reine ECMAScript-Syntax sind — anders als z. B. const enum, das in diesem Modus problematisch wird.
Verfügbar in allen modernen Engines.
bigint ist seit Chrome 67, Firefox 68, Safari 14 und Node.js 10.4 verfügbar — also Baseline seit September 2020. Für Browser-Code ohne Legacy-Anforderungen kannst du bigint heute bedenkenlos verwenden, sofern target: es2020 in der tsconfig.json steht.
bigint in API-Responses meist als String kodiert.
Weil JSON keinen bigint kennt (siehe oben) und Floats keine 64-bit-IDs verlustfrei tragen, geben viele Backends bigint-Werte als String zurück: { id: "9007199254740993" }. Im Frontend dann mit BigInt(json.id) rekonstruieren — oder als String belassen, falls du nur damit rendern willst.