keepass - چگونه «Buffer» را در TypeScript 5.7 به «ArrayBuffer» تبدیل کنیم؟
طبق اعلامیه TypeScript 5.7، من اکنون تحت تأثیر تغییر ES2024 برای بافرها قرار گرفتم. به ویژه این تغییر در ژنریکهای بافر.
من با یک فایل KeePass کار میکنم. برای این کار فایل را بارگذاری میکنم و آن را از طریق پکیج npm "kdbxweb" "^2.1.1" باز میکنم.
زمینه: "typescript": "^5.7.3"، "@types/node": "^22.10.5". (یعنی در حال حاضر آخرین نسخهها)
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)));
// ...
}
بعد از ارتقاء به «ES2024» (از طریق «ESNext»)، npx tsc شکایت میکند:
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
من نمیدانم چگونه این را حل کنم. تابع بارگذاری کتابخانه به این صورت اعلان شده است:
static load(data: ArrayBuffer, credentials: KdbxCredentials, options?: {
preserveXml?: boolean;
}): Promise<Kdbx>;
در حالی که fs.readFileSync() یک Buffer<ArrayBufferLike> برمیگرداند (که از "@types/node": "^22.10.5" میآید)، که باعث میشود ویژگی buffer یک ArrayBufferLike برگرداند.
چطور میتوانم آنها را با هم جمع کنم (بدون انتظار خطای TS یا تبدیل به unknown و غیره)؟ یعنی، چگونه میتوان از Buffer<ArrayBufferLike> به ArrayBuffer به شکل درست تبدیل کرد؟
ریختن کورکورانه به
const fileBuffer = fs.readFileSync(KeePassFilePath) as Buffer<ArrayBuffer>;
خطا را خاموش میکند، اما من چگونه میتوانم نوع واقعی صحیح را بدانم؟ تصور کنید سایر تأمینکنندگان که هیچ نوع تضمینی در مورد واقعی بودن ArrayBuffer ارائه نمیدهند. بنابراین این برای من یک راهحل قابل قبول نیست.
پاسخ شماره ۱
در کد شما بهطور مستقیم از KeePassFileBuffer.buffer استفاده میکنید، که ممکن است باعث ناسازگاری محتوا شود، زیرا این ArrayBuffer داخلی است و ممکن است دادههای اضافی داشته باشد. با روشی که شما استفاده میکنید احتمال آن زیاد نیست، اما بهتر است مطمئن شوید بخش مربوطه را استخراج کنید.
این نحوهای است که میتوانید Buffer<ArrayBufferLike> را به ArrayBuffer تبدیل کنید:
import fs from 'fs/promises';
import path from 'path';
import * as kdbxweb from 'kdbxweb';
import {ProtectedValue} from "kdbxweb";
// Convert Node.js Buffer to ArrayBuffer
function bufferToArrayBuffer(buffer: Buffer): ArrayBuffer {
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer;
}
// And apply that to your code
class SomeClass {
private keepassPassword: ProtectedValue = ProtectedValue.fromString('123');
async getClientSecret(): Promise<string> {
const KeePassFileBuffer = await fs.readFile(path.resolve('user.kdbx'));
const keePassDB: kdbxweb.Kdbx = await kdbxweb.Kdbx.load(bufferToArrayBuffer(KeePassFileBuffer), new kdbxweb.Credentials(this.keepassPassword));
// ....
return '?';
}
}
مستقیماً به مشکل شما مربوط نیست، اما لطفاً توجه کنید که من به API غیرهمزمان Node.js fs/promises تغییر مسیر دادم، که پشتیبانی بهتری از پرامیسها دارد.
پاسخ شماره ۲
به نظر میرسد موارد زیر کار کنند و نوع چکر را راضی کنند، اما احتمالاً مؤثرترین روش برای انجام این کار نیست، زیرا شامل ایجاد چند Uint8Arrays میشود.
const fileBuffer: ArrayBufferLike = new SharedArrayBuffer(16);
const ui8Array: Uint8Array<ArrayBufferLike> = new Uint8Array(fileBuffer);
const actualArrayBuffer: ArrayBuffer = new ArrayBuffer(ui8Array.length);
const actualArrayBufferView: Uint8Array<ArrayBuffer> = new Uint8Array(actualArrayBuffer);
actualArrayBufferView.set(ui8Array);
// actualArrayBuffer now holds the contents of fileBuffer, but is of type ArrayBuffer
