Binary data & typed arrays
Raw byte buffers and the typed views over them, the layer every networking, crypto, and file-I/O path is built on. Every typed array is a general expression and knows its `.buffer` and `.byteOffset`. ArrayBuffer, DataView, SharedArrayBuffer, Atomics, and a real bigint-backed BigInt64Array/DataView 64-bit path are all here, so binary layouts round-trip byte-exactly, an embedded NUL included.
ArrayBuffer
ExactA fixed-length, zero-initialized (calloc'd) raw byte buffer, with .byteLength and .slice(start?, end?) (a copy, with array-slice negative-index/clamping rules). Unlike the TypedArrays below, it's a general expression — it works anywhere, not just in a variable declaration's initializer.
Parameters- byteLengthnumber
- Size of the buffer in bytes.
ArrayBuffer — A zero-filled buffer.
const buf = new ArrayBuffer(8)
console.log(buf.byteLength) // 8
const tail = buf.slice(-4)
console.log(tail.byteLength) // 4Uint8Array / Int8Array / Uint16Array / Int16Array / Uint32Array / Int32Array / Float32Array / Float64Array
ExactTyped views over bytes, in three construction forms: a size (own new zero-filled buffer), an existing ArrayBuffer (a view sharing the same memory — writes through one view are visible through any other view over the same buffer, including a differently-typed one), the sub-range form new XArray(buf, byteOffset, length?), or a number[]/array literal/another TypedArray (a copy). Indexing, .length, the whole number[] HOF/iterator surface, plus the TypedArray-specific .set(source, offset?), .subarray(start?, end?) (a view, not a copy), .byteLength, and .buffer/.byteOffset (a view answers the buffer it was made over; an array with its own storage answers an ArrayBuffer made on first read and kept). Non-clamped writes wrap mod 2^width, matching real JS. Construction is a general expression — usable as a function argument, return value, object field, or method-chain head, not only a variable declaration's initializer.
ReturnsTypedArray — A typed view or an own buffer.
const buf = new ArrayBuffer(8)
const bytes: Uint8Array = new Uint8Array(buf)
const ints: Int32Array = new Int32Array(buf)
bytes[0] = 1
console.log(ints[0]) // 1 — same 4 bytes as an i32BigInt64Array / BigUint64Array
Works, with caveats64-bit typed arrays whose elements are stored as raw i64/u64 but cross the language boundary as real arbitrary-precision bigint handles — writes require a bigint (a plain number is the spec's TypeError), reads wrap losslessly, so values above 2^53 round-trip exactly. Atomics load/store/RMW/compareExchange work on them, lowered to the same seq_cst i64 atomics.
ReturnsBigInt64Array | BigUint64Array — A 64-bit typed array.
const bigs = new BigInt64Array(2)
bigs[0] = 9007199254740993n
console.log(bigs[0]) // 9007199254740993n
const ubigs = new BigUint64Array([18446744073709551615n])
console.log(ubigs[0]) // 18446744073709551615n- Only an explicit method allow-list is supported — indexing r/w,
.length/.byteLength,.at,.set,.subarray,.slice,.fill,.reverse, for-of,Atomics.*; everything else (.map/.filter/.reduce/.indexOf/.sort/.join/iterator objects/…) is a compile-time rejection, never a raw-scalar leak Atomics.wait/notifystayInt32Array-only
Uint8ClampedArray
ExactA Uint8Array whose write path uses the spec's ToUint8Clamp instead of wrapping — values clamp to [0,255], floats round half to even (254.5 → 254, 255.5 → 255), and NaN → 0, on every write (element assignment including compound, construction, .set, .fill, and .map's result store). Reads are plain u8, so the entire read-side method surface works unchanged.
ReturnsUint8ClampedArray — A clamping byte array.
const clamped = new Uint8ClampedArray([-1, 300, 254.5, 255.5])
console.log(clamped[0], clamped[1], clamped[2], clamped[3]) // 0 255 254 255DataView
supportedEndian-controlled binary access over an ArrayBuffer: full get/set × Int8..Uint32/Float16/Float32/Float64 and BigInt64/BigUint64 (real bigint values, unsigned above 2^63 correct) with the spec's per-call littleEndian flag (default big-endian), plus .byteLength/.byteOffset/.buffer (an aliasing-identical ArrayBuffer). V8's RangeErrors on out-of-bounds access and construction, and V8's inspect output. It is a Blob part and a TextDecoder input like any BufferSource.
Parameters- bufferArrayBuffer
- The backing buffer.
- byteOffsetnumber
- Optional start offset.
- byteLengthnumber
- Optional view length.
DataView — A view for scalar reads/writes.
const buf = new ArrayBuffer(12);
const view = new DataView(buf);
view.setUint16(0, 0xCAFE); // big-endian by default
view.setUint32(2, 123456789, true); // explicit little-endian
console.log(view.getUint32(2, true));Blob
ExactAn immutable binary value with a MIME type, built from any iterable of strings, buffers, views and Blobs. The type is lowercased (or empty when not printable ASCII), and endings: 'native' converts line ends. Exposes .size/.type, .slice(start?, end?, contentType?) (a copy; type never inherited, per spec), .text()/.arrayBuffer()/.bytes() settling as Node's reader settles them, and .stream() → ReadableStream<Uint8Array>, one chunk per part.
ReturnsBlob — An immutable binary blob.
const greeting = new Blob(["Hello, ", "world", "!"], { type: "text/plain" })
console.log(greeting.size, greeting.type) // 13 text/plain
console.log(await greeting.text()) // Hello, world!Atomics
Works, with caveatsload/store/add/sub/and/or/xor/exchange/compareExchange on any integer TypedArray including BigInt64Array/BigUint64Array (bigint operands/results), lowered directly to seq_cst LLVM atomics; float TypedArrays are a compile-time rejection. wait(ta, i, expected, timeoutMs?) returns "ok"/"not-equal"/"timed-out"; notify(ta, i, count?) returns the wake count — a portable futex substitute. Atomics.isLockFree(n) is true for 1/2/4/8.
Returnsnumber | bigint | string — The atomic result.
for (let i = 0; i < 1000; i++) {
Atomics.add(cells, 0, 1);
}
const r: string = Atomics.wait(cells, 1, 0, 2000);
console.log("4-byte ops lock-free: " + Atomics.isLockFree(4));waitblocks the whole calling thread (event loop and fibers included) — allowed on the main thread (Node posture); nowaitAsyncwait/notifyareInt32Array-only (spec minus the BigInt64 half)- Index is bounds-unchecked, matching ordinary TypedArray indexing
Node Buffer (Buffer.from/.alloc/.toString(encoding)/.write/etc.)
Works, with caveatsA Buffer IS a Uint8Array — indexing, .length, .slice/.subarray, numeric .fill/.indexOf/.includes, HOFs, for-of, .set, .byteLength, and fs.writeFileSync(buffer) all share the TypedArray machinery; Buffer.from(...)/.alloc(...) are general expressions (call syntax, no vardecl restriction). Codecs both directions — utf8, utf16le/ucs2, hex, base64, base64url, latin1/binary/ascii — plus full read/write{U}Int{8,16,32}{LE,BE} + Float/Double + BigInt64/BigUInt64 accessors with catchable RangeError bounds checks.
ReturnsBuffer — A Uint8Array-backed buffer.
const hello = Buffer.from("Hello"); // utf8 bytes
console.log(Buffer.from("4869", "hex").toString()) // Hi
console.log(hello.toString("base64")) // SGVsbG8=
const pkt = Buffer.alloc(12)
pkt.writeBigInt64BE(9007199254740993n, 4)- String-valued
.indexOf/.includes/.lastIndexOfsearch the needle's UTF-8 bytes, and.fill(string, offset?, end?)repeats the needle's bytes (all no byteOffset/encoding); no 4-arg.write(string, offset, length, encoding)form; no.swap16/32/64,.toJSON,Buffer.of,Buffer.isAscii/Buffer.isUtf8, arbitrary-widthreadIntLE(offset, byteLength),poolSize