Using BigInt and Symbol in TypeScript

Updated: January 7, 2024 By: Guest Contributor Post a comment

Introduction

In the evolving landscape of JavaScript and TypeScript, two notable features that bolster our number handling and property naming capabilities are BigInt and Symbol. This tutorial delves into how these two primitives can be utilized in TypeScript, with practical code samples to guide you along the way.

Understanding BigInt in TypeScript

BigIntis a special numeric type that provides support for integers of arbitrary length. Regular JavaScript numbers are represented as double-precision 64-bit binary format IEEE 754 values, which only safely support numbers between -(253 – 1) and 253 – 1. BigInt allows you to go beyond this range without losing precision.

const hugeNumber: BigInt = BigInt('9007199254740993');
alert(hugeNumber + BigInt(1));  // Output will be 9007199254740994n

Notice that we append an ‘n’ to the end of the number to indicate a BigInt literal.

Performing Arithmetic with BigInt

Arithmetic operations with BigInts are straightforward, much as with the Number type, except that you can’t mix BigInts and regular numbers directly in operations:

// This will cause a TypeError because you cannot mix BigInt and Number types:
const failedSum = hugeNumber + 123; // TypeError: Cannot mix BigInt and other types

// The correct way to perform the operation is to convert all operands to BigInt:
const successfulSum = hugeNumber + BigInt(123); // This will work

Working with JSON and BigInt

Since JSON does not naturally support BigInt, you’ll need to convert it to a string before serializing and parse it back to a BigInt upon deserialization:

const bigintSerial = JSON.stringify({ value: hugeNumber.toString() });
console.log(bigintSerial); // Output: '{"value":"9007199254740993"}'

const bigintParse = JSON.parse(bigintSerial, (key, value) => key === 'value' ? BigInt(value) : value);
console.log(bigintParse.value + BigInt(1));

Embracing Symbol in TypeScript

Symbol is a unique and immutable primitive introduced in ES6 to create unique identifiers for object properties, useful for adding properties that should not overlap with other properties, generally for debugging or private properties.

const uniqueId = Symbol('description');

const myObject = {
  property1: 'Hello',
  [uniqueId]: 'World'
};

console.log(myObject[uniqueId]); // Output will be 'World'

Symbol as Property Keys

Using Symbol as property keys is especially useful since each Symbol is unique and prevents property name collisions.

const symbolOne = Symbol('a');
const symbolTwo = Symbol('a');

console.log(symbolOne == symbolTwo); // Output will be false, even though the descriptions are same.

const obj = {};
obj[symbolOne] = 'Data for symbolOne';
obj[symbolTwo] = 'Data for symbolTwo';

console.log(obj[symbolOne], obj[symbolTwo]); // Output will be 'Data for symbolOne Data for symbolTwo'

System Symbols

There are well-known symbols built into the language, referred to as ‘system symbols’ that represent internal behaviors of JavaScript objects that can be customized by the programmer.

const myArray = [];
myArray[Symbol.toStringTag] = 'MySpecialArray';
console.log(myArray.toString()); // Output: '[object MySpecialArray]'

Advanced Uses

BigInt and Symbol provide depths that can be harnessed for more complex programming paradigms in TypeScript, such as representing very large integers or architecting a codebase with unique and well-organized property names that carry significance across different scopes and modules.

Defining Well-Typed BigInt and Symbol Operations

Within TypeScript, type annotations can be fortified by not only declaring that a variable is a BigInt or Symbol, but also specifying which BigInt or Symbol:

function handleLargeNumbers(num1: bigint, num2: bigint): bigint {
  return num1 * num2;
}

const symbolForAge = Symbol('age');
type Age = typeof symbolForAge;
function getAge(obj: { [key in Age]?: number }): number | undefined {
  return obj[symbolForAge];
}

Conclusion

This tutorial skimmed the surface of the powerful BigInt and Symbol primitives in TypeScript. These features, when leveraged correctly, open a realm of possibilities for handling massive numbers and carving out unique property spaces within your JavaScript objects. Understanding and utilizing BigInt and Symbol will empower you to take advantage of the full scope of TypeScript’s capabilities in your projects.