Recipe · Node and platforms

How do I type Buffers and Uint8Arrays in JSDoc?

  • Node.js (ES modules)
  • Buffer
  • Uint8Array
  • @types/node
  • Checked with TypeScript 5.9

The problem Some of my functions take file contents from fs (a Buffer) and others get bytes from TextEncoder or fetch (a Uint8Array). What type should the @param use, and why does toString('hex') fail on one of them?

The short answer

Take bytes as @param {Uint8Array}. A Node.js Buffer is a subclass of Uint8Array, so the same function accepts a file read from disk and bytes from TextEncoder:

checksum.js checksum.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";

/**
 * @param {Uint8Array} bytes
 * @returns {string}
 */
export function sha256Hex(bytes) {
  return createHash("sha256").update(bytes).digest("hex");
}

/**
 * @param {Uint8Array} bytes
 * @returns {string}
 */
export function toHex(bytes) {
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
}

const file = await readFile("logo.png");
console.log(sha256Hex(file), toHex(new TextEncoder().encode("LAMP-01")));
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";

export function sha256Hex(bytes: Uint8Array): string {
  return createHash("sha256").update(bytes).digest("hex");
}

export function toHex(bytes: Uint8Array): string {
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
}

const file = await readFile("logo.png");
console.log(sha256Hex(file), toHex(new TextEncoder().encode("LAMP-01")));
Functions that take bytes as Uint8Array accept Buffers too.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": ["node"]
  },
  "include": ["*.js"]
}

Inside, use what Uint8Array offers (indexing, Array.from, subarray), and pass the bytes to APIs that accept views, such as hash.update().

Why it works

@types/node declares Buffer as extending Uint8Array, which is how Node.js implements it. A parameter typed with the base class accepts both, and tsc checks that the function only uses members the base class has. Writing to the wider type keeps the function usable outside Node.js too.

The same thing in TypeScript

The TypeScript equivalent tab writes bytes: Uint8Array in the parameter list; the bodies are unchanged.

What goes wrong

Uint8Array has a toString() with no parameters, so the Buffer habit toString("hex") is an argument count error (TS2554). A string is not bytes, and an ArrayBuffer is raw memory without the view methods (TS2345 for both):

checksum.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: checksum.js(4,25): error TS2554: Expected 0 arguments, but got 1. checksum.js(8,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'. checksum.js(10,7): error TS2345: Argument of type 'ArrayBuffer' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'. Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. checksum.js(4,25): error TS2554: Expected 0 arguments, but got 1. checksum.js(8,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'. checksum.js(10,7): error TS2345: Argument of type 'ArrayBuffer' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'. Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more. 7.0.2 : differs, see why TypeScript 7.0.2, run 21 October 2026: differs from 5.9.3. checksum.js(4,25): error TS2554: Expected 0 arguments, but got 1. checksum.js(8,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'. checksum.js(10,7): error TS2740: Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more. checked 21 October 2026
/** @param {Uint8Array} bytes */
export function toHex(bytes) {
  return bytes.toString("hex");error TS2554: Expected 0 arguments, but got 1.
}

toHex("LAMP-01");error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'.
toHex(new ArrayBuffer(8));error TS2345: Argument of type 'ArrayBuffer' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'.
  Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more.
Buffer methods on a Uint8Array, a string for bytes, and an ArrayBuffer for a view.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": ["node"]
  },
  "include": ["*.js"]
}

Encode strings with new TextEncoder().encode(text) (or Buffer.from(text) in Node.js), and wrap an ArrayBuffer with new Uint8Array(buffer).

Under TypeScript 6.0 and 7.0

Every example on this page also runs under TypeScript 6.0.3 and 7.0.2 when this site is built. One of them reports something different from 5.9.3, the version the page describes; the ✗ on its badge links to its entry below.

Some argument errors are reported by what is missing

TypeScript 7.0 · other checker changes

The pattern: An ArrayBuffer passed where a Uint8Array is expected.

Why: 5.9 reports the call (TS2345, "Argument of type 'ArrayBuffer' is not assignable…"); TypeScript 7.0.2 reports the same line as TS2740, listing the properties ArrayBuffer lacks. The port's list of changes does not mention it. The call is an error in both. Source: CHANGES.md: changes between TypeScript 6 and the native port.

Buffer methods on a Uint8Array, a string for bytes, and an ArrayBuffer for a view checksum.js

TypeScript 5.9.3
checksum.js(4,25): error TS2554: Expected 0 arguments, but got 1.
checksum.js(8,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'.
checksum.js(10,7): error TS2345: Argument of type 'ArrayBuffer' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'.
  Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more.
TypeScript 6.0.3same as 5.9.3

The same errors as 5.9.3.

TypeScript 7.0.2differs from 5.9.3
checksum.js(4,25): error TS2554: Expected 0 arguments, but got 1.
checksum.js(8,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Uint8Array<ArrayBufferLike>'.
checksum.js(10,7): error TS2740: Type 'ArrayBuffer' is missing the following properties from type 'Uint8Array<ArrayBufferLike>': BYTES_PER_ELEMENT, buffer, byteOffset, copyWithin, and 24 more.

What works in every version: Wrap the buffer: new Uint8Array(buffer).

The example Functions that take bytes as Uint8Array accept Buffers too on this page shows it, with the same result under every version.

Gotchas

  • Buffer’s own methods need @param {Buffer}. If the function really needs readUInt32BE or toString("base64"), type the parameter as Buffer and accept that it is Node.js only.
  • @types/node 24 names some buffers NonSharedBuffer. It appears in messages for values like readFile’s result; it is a Buffer backed by an ordinary ArrayBuffer.
  • subarray shares memory, slice on a Buffer does too. On a Uint8Array, slice copies; on a Buffer, slice and subarray both return a view of the same memory, and both are typed as Buffer. The types do not show the difference, so prefer subarray when you mean a view.

Questions

What does Uint8Array<ArrayBufferLike> in error messages mean?

Since TypeScript 5.7, typed arrays are generic over the kind of buffer behind them. Uint8Array with no argument means Uint8Array<ArrayBufferLike>, which accepts views of an ArrayBuffer or a SharedArrayBuffer; you rarely need to write the argument yourself.

How do I turn a Uint8Array into a Buffer?

Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength) shares the memory without copying; Buffer.from(bytes) copies it.

Sources

Last reviewed 21 October 2026.