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:
- Binary Number System - Understanding bits and bytes will help you grasp why different types have different ranges
- Signed and Unsigned Integers - Explains how negative numbers are stored in binary (two's complement)
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:
Prefix | Meaning | Example |
---|---|---|
Int | Signed integer (can be negative) | Int8Array, Int16Array |
Uint | Unsigned integer (positive only) | Uint8Array, Uint32Array |
Float | Floating-point (decimals) | Float32Array, Float64Array |
Clamped | Special wrapping behavior | Uint8ClampedArray |
Number | Bits | Bytes | Memory per element |
---|---|---|---|
8 | 8 | 1 | Smallest |
16 | 16 | 2 | Medium |
32 | 32 | 4 | Large |
64 | 64 | 8 | Largest |
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?
- Exact representation - No rounding errors
- Faster operations - CPUs handle integers more efficiently
- Smaller size - Can use fewer bits for limited ranges
- 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?
- Decimal support - For measurements, coordinates, percentages
- Large range - Can represent very big or very small numbers
- Scientific computing - Standard for calculations
- 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?
- Larger positive range - Uint8 goes to 255, Int8 only to 127
- Natural for sizes - File sizes, pixel values, counts
- Matches hardware - Memory addresses are unsigned
- 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?
- Represent negatives - Temperature, differences, offsets
- Mathematical operations - Subtraction can go negative
- Real-world data - Account balances, elevations, directions
- 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:
Type | Range | Total Values | Allows Negatives? |
---|---|---|---|
Uint8 | 0 to 255 | 256 | No |
Int8 | -128 to 127 | 256 | Yes |
Uint16 | 0 to 65,535 | 65,536 | No |
Int16 | -32,768 to 32,767 | 65,536 | Yes |
Uint32 | 0 to 4,294,967,295 | ~4.3 billion | No |
Int32 | -2,147,483,648 to 2,147,483,647 | ~4.3 billion | Yes |
Summary: Complete Type Reference
Let's consolidate everything into a quick reference guide.
The Complete Family Table
Type | Bytes | Range | Decimals? | Negatives? | Overflow | Primary Use Cases |
---|---|---|---|---|---|---|
Int8Array | 1 | -128 to 127 | No | Yes | Wraps | Small signed values, temperature |
Uint8Array | 1 | 0 to 255 | No | No | Wraps | Files, bytes, RGB, ASCII |
Uint8ClampedArray | 1 | 0 to 255 | No | No | Clamps | Canvas pixels |
Int16Array | 2 | -32,768 to 32,767 | No | Yes | Wraps | Audio samples, sensors |
Uint16Array | 2 | 0 to 65,535 | No | No | Wraps | Unicode, ports, medium IDs |
Int32Array | 4 | ±2.1 billion | No | Yes | Wraps | Unix timestamps, large counters |
Uint32Array | 4 | 0 to 4.3 billion | No | No | Wraps | Hashes, large IDs, packed colors |
Float32Array | 4 | ±3.4×10^38 | Yes (~7 digits) | Yes | Special | 3D graphics, games |
Float64Array | 8 | ±1.7×10^308 | Yes (~15 digits) | Yes | Special | GPS, 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
Related Topics
Deepen your binary data expertise:
- DataView: Flexible Binary Data Access - Handle mixed data types and control byte order
- Blob and File APIs - Work with files in the browser
- Streams: Processing Data Incrementally - Handle large files efficiently
Understand the underlying concepts:
- Binary Number System - How computers represent numbers
- Hexadecimal Number System - Read binary data in hex format
- Signed and Unsigned Integers - Two's complement explained
- Character Encoding - Convert between text and binary
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:
- Use the smallest type that fits - saves memory and improves performance
- Integers for exact values - counts, IDs, pixel values
- Floats for measurements - coordinates, temperatures, scientific data
- Unsigned for positive-only data - doubles your positive range
- 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!