Skip to Content
Course content

181: BigInt Support in TypeScript

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this bug trip up plenty of developers, usually when they're integrating with a backend that uses 64-bit integers for database IDs or financial balances. You're writing your logic, everything looks fine in your local tests with small numbers, and then suddenly, in production, your IDs start "rounding off" or comparing as equal when they aren't.

// A common scenario: Processing large database IDs from an API
function checkIdMatch(storedId: number, providedId: number) {
  return storedId === providedId;
}

const dbId = 9007199254740993; // Just slightly over Number.MAX_SAFE_INTEGER
const inputId = 9007199254740992;

console.log(checkIdMatch(dbId, inputId)); // Returns: true

Wait, what? These numbers are clearly different, but TypeScript (and JavaScript) tells us they are the same. This happens because the number type is a 64-bit float. Once you cross the "safe integer" threshold (Number.MAX_SAFE_INTEGER, which is 253 - 1), the precision drops. The engine literally can't tell the difference between those two massive integers anymore.

Breaking the Safe Integer Limit

To fix this, we need a type that doesn't rely on floating-point math. That's where bigint comes in. It's a primitive specifically designed to handle integers of arbitrary length. If you're dealing with 64-bit IDs from a SQL database or counting something that could realistically exceed 9 quadrillion, you cannot use number.

You can create a bigint by appending an n to the end of an integer literal, or by using the BigInt() constructor.

// The fixed version
function checkIdMatch(storedId: bigint, providedId: bigint) {
  return storedId === providedId;
}

const dbId = 9007199254740993n; // Notice the 'n'
const inputId = 9007199254740992n;

console.log(checkIdMatch(dbId, inputId)); // Returns: false

Handling the BigInt Type Mismatch

Here is the part that usually frustrates people: bigint and number are completely different types. You cannot mix them in mathematical operations. If you try to add a number to a bigint, TypeScript will throw a compiler error, and the runtime will throw a TypeError.

const balance = 100n;
const fee = 5;

// ❌ This will crash: "Cannot mix BigInt and other types"
const total = balance - fee; 

I've found the cleanest way to handle this is to be intentional about your conversions. If you know a value is a small constant, just make it a bigint literal. If it's coming from a variable, cast it explicitly.

const balance = 100n;
const fee = 5;

// ✅ Convert the number to BigInt first
const total = balance - BigInt(fee);

console.log(total); // 95n

One last tip: be careful with JSON.stringify(). By default, JSON doesn't know what a bigint is and will throw an error. You'll need to convert your bigints to strings before sending them over the wire, which is actually best practice anyway since most JSON parsers in other languages will treat large numbers as floats and introduce the same precision bugs we just fixed.




📋 Practical Task

Build a High-Precision Nano-Timestamp Converter

In high-frequency trading or distributed logging, timestamps are often tracked in nanoseconds (10-9 seconds), which easily exceeds the Number.MAX_SAFE_INTEGER limit.

Your Task: Create a function called convertNanoToMilli that takes a nanosecond timestamp as a bigint and returns the equivalent millisecond timestamp as a bigint.

  • The function must accept a parameter of type bigint.
  • It should divide the nanoseconds by 1,000,000 to get milliseconds.
  • The function must return a bigint.
  • Test your function with the value 1672531200000000000n (a realistic nanosecond timestamp).

Ensure you are using bigint literals and type annotations throughout to prevent any precision loss or type mismatch errors.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.