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:
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")));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):
/** @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.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
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 needsreadUInt32BEortoString("base64"), type the parameter asBufferand accept that it is Node.js only. @types/node24 names some buffersNonSharedBuffer. It appears in messages for values likereadFile’s result; it is aBufferbacked by an ordinaryArrayBuffer.subarrayshares memory,sliceon aBufferdoes too. On aUint8Array,slicecopies; on aBuffer,sliceandsubarrayboth return a view of the same memory, and both are typed asBuffer. The types do not show the difference, so prefersubarraywhen 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
- Buffer (Buffers and TypedArrays) · Node.js documentation
- Uint8Array · MDN Web Docs
- TypeScript 5.7 release notes (TypedArrays are now generic over ArrayBufferLike) · TypeScript handbook
Last reviewed 21 October 2026.