As you noted, @types/node includes only a stub for the webcrypto interface. One workaround is to extend the crypto module declaration to declare webcrypto.subtle as SubtleCrypto from the DOM type definitions:
// src/types/index.d.ts
declare module "crypto" {
namespace webcrypto {
const subtle: SubtleCrypto;
}
}
This allows writing a module like:
// src/digest.ts:
import * as crypto from "crypto";
// subtle has type SubtleCrypto, from the DOM type definitions
const { subtle } = crypto.webcrypto;
// Generate a cryptographic digest of the given message
export async function digest(message?: string, algorithm = "SHA-512") {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hash = await subtle.digest(algorithm, data);
return hash;
}
To use SubtleCrypto, the project must enable the DOM type definitions by adding dom to the lib array in tsconfig.json. For example, with the following packages installed:
$ npm install -D typescript@4.6 @types/node@17 @tsconfig/node17
and a tsconfig.json containing:
{
"extends": "@tsconfig/node17/tsconfig.json",
"compilerOptions": {
"lib": ["dom"],
"outDir": "dist",
"typeRoots": ["./node_modules/@types", "./src/types"]
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}
you can write an entrypoint that calls digest and prints the result:
// src/index.ts
import { digest } from "./digest";
const message = "Hello, World!";
(async () => {
const digestBuffer = await digest(message);
console.log(Buffer.from(new Uint8Array(digestBuffer)).toString("hex"));
})();
This builds and runs, like:
$ npx tsc && node dist/index.js
374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387