Skip to main content

The Complete Typed Array Family: Choosing the Right Type

You've learned the fundamentals of Typed Arrays—how they provide typed access to ArrayBuffer and why they're essential for binary data. But we've only scratched the surface by focusing on Uint8Array.

Here's the truth: JavaScript provides 9 different Typed Array types, each designed for specific kinds of numbers. Choosing the right type isn't just about making your code work—it's about making it efficient, correct, and maintainable.

Consider this scenario:

// Storing GPS coordinates
const location1 = new Uint8Array([40, 74]); // Wrong!
console.log(location1); // [40, 74] - but coordinates have decimals!

const location2 = new Float64Array([40.748817, -73.985428]); // Correct!
console.log(location2); // [40.748817, -73.985428] - precise!

The wrong choice loses precision, corrupts data, or wastes memory. The right choice ensures correctness, optimizes performance, and makes your intent clear.

In this guide, you'll master all 9 Typed Array types. You'll understand not just what each type does, but when and why to use it. We'll explore integers vs decimals, signed vs unsigned, and the critical concept of value ranges.

What You Need to Know First

Required reading:

  • Typed Arrays Fundamentals - You must understand what Typed Arrays are, how they work as views, and the three creation methods

Helpful background:

What you should already know:

  • How to create Typed Arrays (from size, buffer, or values)
  • The difference between views and copies
  • Basic ArrayBuffer concepts
  • That Uint8Array stores numbers from 0 to 255

If you skipped the fundamentals:

Please read Typed Arrays Fundamentals first. This article builds directly on those concepts. Without understanding views, buffers, and the basics of Uint8Array, the rest won't make sense.

What We'll Cover in This Article

By the end of this guide, you'll understand:

  • The complete family tree of all 9 Typed Array types
  • The difference between integer and floating-point types
  • What "signed" and "unsigned" mean and when each matters
  • Why bit size (8-bit, 16-bit, 32-bit) determines value ranges
  • Value wrapping vs value clamping (Uint8Array vs Uint8ClampedArray)
  • When to use each type for optimal performance and correctness
  • Memory efficiency: why choosing the right type saves space
  • How to convert between different Typed Array types
  • Real-world use cases for each type
  • Decision-making frameworks for type selection

What We'll Explain Along the Way

These concepts will be explained with detailed examples:

  • Bits and bytes - How size determines capacity (with visual diagrams)
  • Integer representation - How whole numbers are stored
  • Floating-point representation - How decimals are stored
  • Two's complement - How signed integers handle negatives
  • Precision limits - Why Float32 and Float64 differ
  • Byte order (endianness) - Mentioned when relevant for multi-byte types
  • Value overflow - What happens at the boundaries

The Typed Array Family Tree

JavaScript provides exactly 9 Typed Array types. Let's start with the big picture before diving into each one.

The Complete Family

Understanding the Naming Convention

Every Typed Array name tells you exactly what it does. Let's decode the pattern:

Uint16Array
│││ ││ │
│││ ││ └─ "Array" - it's an array-like collection
│││ │└── Number of BITS (not bytes!)
│││ └─── Type identifier
││└────── Optional: "Clamped" (special behavior)
│└─────── "Float" for decimals, empty for integers
└──────── "U" = Unsigned (positive only)
Empty = Signed (can be negative)

Decoding examples:

// Int8Array
// ├─ Int = Integer (whole numbers only)
// ├─ 8 = 8 bits = 1 byte per element
// └─ No "U" = Signed (allows negatives)

// Uint16Array
// ├─ Uint = Unsigned Integer (positive only)
// ├─ 16 = 16 bits = 2 bytes per element
// └─ "U" prefix = Unsigned

// Float32Array
// ├─ Float = Floating-point (decimals allowed)
// ├─ 32 = 32 bits = 4 bytes per element
// └─ Float types are always signed

// Uint8ClampedArray
// ├─ Uint8 = Unsigned 8-bit integer
// ├─ Clamped = Special: limits values instead of wrapping
// └─ Used for canvas pixel data

Quick reference table:

PrefixMeaningExample
IntSigned integer (can be negative)Int8Array, Int16Array
UintUnsigned integer (positive only)Uint8Array, Uint32Array
FloatFloating-point (decimals)Float32Array, Float64Array
ClampedSpecial wrapping behaviorUint8ClampedArray
NumberBitsBytesMemory per element
881Smallest
16162Medium
32324Large
64648Largest

Integers vs Floating-Point: The Fundamental Split

Before diving into individual types, let's understand the two fundamental categories: integers and floating-point numbers.

Integer Types: Whole Numbers Only

Integers are whole numbers—no decimal point, no fractions. They're exact representations with no rounding errors.

// Valid integers
const integers = [0, 1, -5, 42, 100, -128, 32767];

// Not integers (will be truncated)
const notIntegers = [3.14, 2.71, -0.5, 10.9];

Why use integers?

  1. Exact representation - No rounding errors
  2. Faster operations - CPUs handle integers more efficiently
  3. Smaller size - Can use fewer bits for limited ranges
  4. Natural for counting - Pixels, bytes, array indices, IDs

Integer example:

const pixels = new Uint8Array([255, 128, 0]); // RGB: Orange
console.log(pixels[0]); // 255 - exact
console.log(pixels[1]); // 128 - exact
console.log(pixels[2]); // 0 - exact

// Integers are perfect for discrete values
const ages = new Uint8Array([25, 30, 42, 18]);
const counts = new Uint16Array([100, 500, 1000]);

What happens with decimals:

const arr = new Uint8Array(3);

arr[0] = 10.1; // Truncates to 10 (not rounded!)
arr[1] = 10.9; // Truncates to 10
arr[2] = 99.999; // Truncates to 99

console.log(arr); // Uint8Array(3) [10, 10, 99]

// The decimal part is simply cut off
// This is called "truncation" - think floor() for positives

Floating-Point Types: Decimals Allowed

Floating-point numbers can represent decimals, but they're approximations—they can have tiny rounding errors.

// Valid floating-point
const floats = [3.14, -0.5, 0.0001, 1000.999];

Why use floating-point?

  1. Decimal support - For measurements, coordinates, percentages
  2. Large range - Can represent very big or very small numbers
  3. Scientific computing - Standard for calculations
  4. Real-world data - Temperature, distance, money (with caveats)

Floating-point example:

const coords = new Float64Array([40.748817, -73.985428]);
console.log(coords[0]); // 40.748817 - precise
console.log(coords[1]); // -73.985428 - precise

const temperatures = new Float32Array([-5.5, 20.3, 37.2]);
console.log(temperatures); // Float32Array(3) [-5.5, 20.3, 37.2]

The precision problem:

// Float32: ~7 significant digits
const f32 = new Float32Array([3.141592653589793]);
console.log(f32[0]); // 3.1415927410125732
// ^^^^^^^^^ - only ~7 digits accurate

// Float64: ~15 significant digits
const f64 = new Float64Array([3.141592653589793]);
console.log(f64[0]); // 3.141592653589793
// ^^^^^^^^^^^^^^^^^ - all 15+ digits preserved

// Why? Storage format limits precision

Visual Comparison

When to Choose Each

Use integers when:

  • Counting things (pixels, items, people)
  • Storing IDs or indices
  • Working with bytes directly
  • Need exact values
  • Performance is critical

Use floating-point when:

  • Measurements with decimals (distance, weight, temperature)
  • GPS coordinates
  • Percentages or ratios
  • Scientific calculations
  • Graphics coordinates (3D positions)

Signed vs Unsigned: Handling Negative Numbers

Within integer types, there's another critical distinction: signed vs unsigned.

Unsigned: Positive Numbers Only

Unsigned integers can only represent zero and positive numbers. They use all their bits for magnitude.

// Uint8Array: 0 to 255 (all positive)
const unsigned = new Uint8Array(4);

unsigned[0] = 0; // Min value ✓
unsigned[1] = 128; // Middle ✓
unsigned[2] = 255; // Max value ✓
unsigned[3] = -1; // Wraps to 255 (no negatives!)

console.log(unsigned); // Uint8Array(4) [0, 128, 255, 255]

Why unsigned?

  1. Larger positive range - Uint8 goes to 255, Int8 only to 127
  2. Natural for sizes - File sizes, pixel values, counts
  3. Matches hardware - Memory addresses are unsigned
  4. Byte representation - Raw bytes are 0-255

Visual representation of Uint8 (unsigned):

Binary    Decimal
00000000 = 0 (minimum)
00000001 = 1
01111111 = 127
10000000 = 128
11111111 = 255 (maximum)

All 8 bits used for magnitude
Range: 2^8 = 256 values (0 to 255)

Signed: Negative Numbers Allowed

Signed integers can represent both negative and positive numbers. They sacrifice half their range to include negatives.

// Int8Array: -128 to 127 (includes negatives)
const signed = new Int8Array(5);

signed[0] = -128; // Min value ✓
signed[1] = -1; // Negative ✓
signed[2] = 0; // Zero ✓
signed[3] = 1; // Positive ✓
signed[4] = 127; // Max value ✓

console.log(signed); // Int8Array(5) [-128, -1, 0, 1, 127]

Why signed?

  1. Represent negatives - Temperature, differences, offsets
  2. Mathematical operations - Subtraction can go negative
  3. Real-world data - Account balances, elevations, directions
  4. Delta values - Changes that can be positive or negative

Visual representation of Int8 (signed):

Binary    Decimal
10000000 = -128 (minimum - MSB is sign bit)
11111111 = -1
00000000 = 0
00000001 = 1
01111111 = 127 (maximum)

MSB (Most Significant Bit) is the sign bit:
0 = positive
1 = negative

Remaining 7 bits for magnitude
Range: 2^8 = 256 values (-128 to 127)

Range Comparison

Quick reference:

TypeRangeTotal ValuesAllows Negatives?
Uint80 to 255256No
Int8-128 to 127256Yes
Uint160 to 65,53565,536No
Int16-32,768 to 32,76765,536Yes
Uint320 to 4,294,967,295~4.3 billionNo
Int32-2,147,483,648 to 2,147,483,647~4.3 billionYes

Summary: Complete Type Reference

Let's consolidate everything into a quick reference guide.

The Complete Family Table

TypeBytesRangeDecimals?Negatives?OverflowPrimary Use Cases
Int8Array1-128 to 127NoYesWrapsSmall signed values, temperature
Uint8Array10 to 255NoNoWrapsFiles, bytes, RGB, ASCII
Uint8ClampedArray10 to 255NoNoClampsCanvas pixels
Int16Array2-32,768 to 32,767NoYesWrapsAudio samples, sensors
Uint16Array20 to 65,535NoNoWrapsUnicode, ports, medium IDs
Int32Array4±2.1 billionNoYesWrapsUnix timestamps, large counters
Uint32Array40 to 4.3 billionNoNoWrapsHashes, large IDs, packed colors
Float32Array4±3.4×10^38Yes (~7 digits)YesSpecial3D graphics, games
Float64Array8±1.7×10^308Yes (~15 digits)YesSpecialGPS, science, high precision

Quick Selection Guide

Need integers (whole numbers)?

  • Range 0-255: Uint8Array (or Uint8ClampedArray for canvas)
  • Range -128 to 127: Int8Array
  • Range 0-65K: Uint16Array
  • Range -32K to 32K: Int16Array
  • Range 0-4.3B: Uint32Array
  • Range ±2.1B: Int32Array

Need decimals?

  • Low precision OK (~7 digits): Float32Array
  • High precision needed (~15 digits): Float64Array

Common scenarios:

  • Reading files: Uint8Array
  • Canvas pixels: Uint8ClampedArray
  • 3D graphics: Float32Array
  • GPS coordinates: Float64Array
  • Audio data: Int16Array
  • Network ports: Uint16Array

Memory Usage Comparison

For 1 million elements:

Int8/Uint8: ████ 0.95 MB (most efficient)
Int16/Uint16: ████████ 1.91 MB
Int32/Uint32: ████████████████ 3.81 MB
Float32: ████████████████ 3.81 MB
Float64: ████████████████████████████████ 7.63 MB (least efficient)
Regular Array: ████████████████████████████████████████ ~8-16 MB (varies)

Quick Reference Card

// INTEGER TYPES (whole numbers only)

// 8-bit (1 byte)
Int8Array; // -128 to 127 | Temperature, small deltas
Uint8Array; // 0 to 255 | Files, bytes, RGB, ASCII
Uint8ClampedArray; // 0 to 255 (clamped) | Canvas pixels ONLY

// 16-bit (2 bytes)
Int16Array; // -32,768 to 32,767 | Audio samples, sensors
Uint16Array; // 0 to 65,535 | Unicode, ports, medium IDs

// 32-bit (4 bytes)
Int32Array; // ±2.1 billion | Timestamps (until 2038!)
Uint32Array; // 0 to 4.3 billion | Large IDs, hashes, colors

// FLOATING-POINT TYPES (decimals allowed)

// 32-bit (4 bytes)
Float32Array; // ~7 digits precision | 3D graphics, games

// 64-bit (8 bytes)
Float64Array; // ~15 digits precision | GPS, science, finance

// QUICK SELECTION
// File data → Uint8Array
// Canvas pixels → Uint8ClampedArray
// 3D graphics → Float32Array
// GPS coords → Float64Array
// Audio samples → Int16Array
// Ports/Unicode → Uint16Array
// Large IDs → Uint32Array

// MEMORY EFFICIENCY (per 1000 elements)
// Int8/Uint8: 1 KB
// Int16/Uint16: 2 KB
// Int32/Uint32: 4 KB
// Float32: 4 KB
// Float64: 8 KB

What's Next?

You've completed your journey through the Typed Array family! Now you're ready for advanced real-world applications.

Next article: Typed Arrays in Practice: Real-World Applications

In the final article, you'll build complete applications:

  • Complete PNG image parser (reading dimensions, color data, metadata)
  • WAV audio file generator (creating playable audio files)
  • Canvas image filters (grayscale, sepia, blur, brightness)
  • Multiple views pattern (interpreting same data differently)
  • Binary protocol encoder/decoder (custom message formats)
  • Performance optimization techniques
  • Production-ready error handling

Deepen your binary data expertise:

Understand the underlying concepts:

Final Thoughts

You've now mastered the complete Typed Array family! You understand:

  • Why JavaScript has 9 different types - each optimized for specific data
  • How to choose the right type - based on range, precision, and memory needs
  • The fundamental distinctions - integers vs floats, signed vs unsigned
  • Memory efficiency - using the smallest type that fits your data
  • Type characteristics - ranges, sizes, and behaviors

Remember these key principles:

  1. Use the smallest type that fits - saves memory and improves performance
  2. Integers for exact values - counts, IDs, pixel values
  3. Floats for measurements - coordinates, temperatures, scientific data
  4. Unsigned for positive-only data - doubles your positive range
  5. High precision for critical data - GPS, science need Float64

With this knowledge, you're ready to work with binary data at a professional level. Whether you're parsing files, processing images, handling audio, or working with 3D graphics, you now know exactly which type to reach for.

Next up: Put all this knowledge into practice with complete, production-ready examples in the final article of this series!