According to the TypeScript 5.7 announcement, I am now affected by the ES2024 change for Buffers. Especially this change of Buffer Generics.
I am working with a KeePass file. For that I load the file and open it via npm package "kdbxweb" "^2.1.1"
.
Context: "typescript": "^5.7.3"
, "@types/node": "^22.10.5"
. (i.e. currently latest versions)
import fs from 'fs';
import path from 'path';
import * as kdbxweb from 'kdbxweb';
async getClientSecret(): Promise<string> {
const fileBuffer: Buffer<ArrayBufferLike> = fs.readFileSync(KeePassFilePath);
const keePassFileBuffer: ArrayBufferLike = fileBuffer.buffer;
const keePassDB: kdbxweb.Kdbx = await kdbxweb.Kdbx.load(keePassFileBuffer, new kdbxweb.Credentials(kdbxweb.ProtectedValue.fromString(myPW)));
// ...
}
After the upgrade to "ES2024" (via "ESNext"), npx tsc
complains:
error TS2345: Argument of type 'ArrayBufferLike' is not assignable to parameter of type 'ArrayBuffer'.
Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength
I don't know how to solve this. The library's load function is declared as:
static load(data: ArrayBuffer, credentials: KdbxCredentials, options?: {
preserveXml?: boolean;
}): Promise<Kdbx>;
While fs.readFileSync()
returns a Buffer<ArrayBufferLike>
(coming from "@types/node": "^22.10.5"
), which makes the buffer
property return an ArrayBufferLike
.
How can I bring them together (without expecting the TS error or casting to unknown
etc.)? I.e. how to convert from Buffer<ArrayBufferLike>
to ArrayBuffer
properly?
Blindly casting to
const fileBuffer = fs.readFileSync(KeePassFilePath) as Buffer<ArrayBuffer>;
does silence the error, but how am I supposed to know the correct actual type? Imagine other suppliers, which don't give some kind of guarantee about this being an actual ArrayBuffer
. So this is not a viable solution to me.
As ArrayBufferLike
can be at least either an ArrayBuffer | Shared ArrayBuffer | ...
, I found that we can wrap the Buffer<ArrayBufferLike>
into an Uint8Array
to guarantee an ArrayBuffer
:
import fs from 'fs';
import path from 'path';
import * as kdbxweb from 'kdbxweb';
async getClientSecret(): Promise<string> {
const fileBuffer: Buffer<ArrayBufferLike> = fs.readFileSync(KeePassFilePath);
const keePassFileBuffer: ArrayBuffer = new Uint8Array(fileBuffer).buffer;
const keePassDB: kdbxweb.Kdbx = await kdbxweb.Kdbx.load(keePassFileBuffer, new kdbxweb.Credentials(kdbxweb.ProtectedValue.fromString('123')));
// ...
}