javascript - I TypeScript 5.6+ är `Buffer` inte tilldelningsbar till `ArrayBufferView` eller `Uint8Array | DataView`


Försöker uppgradera till TypeScript 5.6 Beta, får jag följande felmeddelanden i node_modules. Jag gjorde inga andra ändringar, så vad ska jag göra för att åtgärda dessa fel?

node_modules/@types/node/buffer.d.ts:632:19 - error TS2430: Interface 'Buffer' incorrectly extends interface 'Uint8Array'.
  The types returned by 'reverse()' are incompatible between these types.
    Type 'this' is not assignable to type 'Uint8Array'.
      Type 'Buffer' is not assignable to type 'Uint8Array'.
        The types returned by 'slice(...).entries()' are incompatible between these types.
          Type 'IterableIterator<[number, number]>' is missing the following properties from type 'BuiltinIterator<[number, number], undefined, any>': map, filter, take, drop, and 8 more.

632         interface Buffer extends Uint8Array {
                      ~~~~~~
node_modules/@types/node/fs/promises.d.ts:56:66 - error TS2344: Type 'Buffer' does not satisfy the constraint 'ArrayBufferView'.
  Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.
    Type 'Buffer' is not assignable to type 'Uint8Array'.
      The types returned by 'entries()' are incompatible between these types.
        Type 'IterableIterator<[number, number]>' is missing the following properties from type 'BuiltinIterator<[number, number], undefined, any>': map, filter, take, drop, and 8 more.

56     interface FileReadOptions<T extends NodeJS.ArrayBufferView = Buffer> {
                                                                    ~~~~~~
node_modules/@types/node/fs/promises.d.ts:238:49 - error TS2344: Type 'Buffer' does not satisfy the constraint 'ArrayBufferView'.
  Type 'Buffer' is not assignable to type 'Uint8Array | DataView'.
    Type 'Buffer' is not assignable to type 'Uint8Array'.
      The types returned by 'entries()' are incompatible between these types.
        Type 'IterableIterator<[number, number]>' is missing the following properties from type 'BuiltinIterator<[number, number], undefined, any>': map, filter, take, drop, and 8 more.

238         read<T extends NodeJS.ArrayBufferView = Buffer>(options?: FileReadOptions<T>): Promise<FileReadResult<T>>;
                                                    ~~~~~~

Observera: när jag använde en nyare version av TypeScript 5.6 verkar omnämnanden av BuiltinIterator<[number, number], ...> ha ersatts med ArrayIterator<number>.

Svar #1

Kort svar

Du behöver en ny version av Node.js-typerna.

npm update @types/node --save-dev

or if you need a specific version
npm install -D @types/node@16
npm install -D @types/node@18
npm install -D @types/node@20
npm install -D @types/node@22

Långt svar

Först beskriver IterableIterator en typ som både är Iterable (den kan skapa en Iterator genom att anropa someValue[Symbol.iterator()]), och är själv en Iterator (du kan anropa saker som next() på den om och om igen tills den inte har några värden kvar).

Iterables (och IterableIterators) är bra eftersom de kan användas på alla möjliga sätt i JavaScript - men många människor saknade metoder på Arrays som map, filter, osv. Så ett nyligen föreslaget förslag lades fram i JavaScript/ECMAScript för att ta med många användbara metoder från Array (plus några till). Du kan anpassa alla befintliga Iterables till denna nya typ med Iterable.from:

Iterator.from(...).filter(someFunction);

Nu närhelst en inbyggd metod, eller en generator, producerar en av dessa IterableIterator, stöds den av metoderna på Iterator.prototype, och du kan kalla något som map, filter, etc.

new Uint8Array(100).entries().map(x => x)

Observera dock att vi pratar om ett nytt körtidsvärde som kallas Iterator. Du kan referera till Iterator och Iterator.prototype som faktiska värden i JavaScript. Detta är lite besvärligt eftersom TypeScript definierar sin egen sak kallad Iterator som finns enbart för typkontroll. Så på grund av denna olyckliga namnkonflikt behöver TypeScript införa en separat typ för att beskriva dessa inbyggda itererbara iterators.

TypeScript 5.6 introducerar en ny typ kallad IteratorObject (och några undertyper som ArrayIterator). Många inbyggda samlingar och metoder producerar denna typ, så många metoder var tvungna att uppdateras för att producera den.

Så hur orsakar detta problem i Node.js? Jo, i @types/node är Buffer i princip en subtyp av Uint8Array. Buffer omdeklarerade onödigt entries()-metoden på ett sätt som kopierade den gamla signaturen:

    /**
     * Returns an array of key, value pairs for every entry in the array
     */
    entries(): IterableIterator<[number, number]>;
}

Men i TypeScript 5.6 har Uint8Array uppdaterats för att använda en signatur som:

    entries(): ArrayIterator<number>;
}

Detta fick de två att avvika på något inkompatibla sätt.

Så nyligen har @types/node uppdaterats för att helt undvika problemet.

Relaterade artiklar