typescript - Varför ger det ett fel att skicka giltiga typer till en typad arraykonstruktör


Du kan skicka ett nummer, en JavaScript-native-array, eller en annan typedarray (och andra saker) till en typed array-view-konstruktor

const a = new Int32Array(3);
const b = new Int32Array([1, 2, 3]);
const c = new Int32Array(new Int32Array([1, 2, 3]));

Med tanke på det, skulle jag förvänta mig att den här TypeScript-koden fungerar

function make(data: number | number[] | Int32Array) {
  return new Int32Array(data);
} 

TypeScript-lekplats

men det misslyckas med

No overload matches this call.
 The last overload gave the following error.
   Argument of type 'number | Int32Array | number[]' is not assignable to parameter of type 'ArrayBufferLike'.
     Type 'number' is not assignable to type 'ArrayBufferLike'.(2769)

Gör jag något fel? Är detta en känd begränsning?

Svar #1

TypeScript-bibliotekets typings för de typade array-konstruktorerna (såsom Int32Array-konstruktorn, från lib.es5.d.ts, lib.es2015.iterable.d.ts och lib.es2017.typedarrays.d.ts, varje tillägg motsvarande ändringar i språkstandarden över tid) implementeras som en serie överlagringar. Det vill säga, det finns flera anropssignaturer:

interface Int32ArrayConstructor {
  // from lib.es5.d.ts
  new(length: number): Int32Array;
  new(array: ArrayLike<number> | ArrayBufferLike): Int32Array;
  new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int32Array;
  // from lib.es2015.iterable.d.ts
  new(elements: Iterable<number>): Int32Array;
  // from lib.es2017.typedarrays.d.ts
  new(): Int32Array;
}

Och när du anropar en överlagrad funktion (eller new en överlagrad konstruktor) i TypeScript, löses det till exakt en anropssignatur. Om ingen enskild anropssignatur är lämplig, misslyckas anropet. Typkontrollanten försöker inte syntetisera kombinerade anropssignaturer som skulle acceptera en union av de parametrar som accepteras av individuella anropssignaturer. Det finns ett långvarigt öppet problem för detta slags stöd, vid microsoft/TypeScript#14107. Tills och om detta ändras måste du arbeta runt det.


Helt klart den enklaste lösningen här är att använda en typasserning:

return new Int32Array(data as number); // for example

Om du vill "fixa" Int32Array kan du slå ihop med en mer tillåtande anropssignatur (kom ihåg att använda global förstärkning om du är i en modul och inte skriver i ambient scope):

// declare global { // use this if you are in a module
interface Int32ArrayConstructor {
  new(x?: number | Iterable<number> | ArrayBufferLike): Int32Array;
}
// }

Och sedan kommer ditt ursprungliga samtal att fungera utan problem.

Lekplatslänk till kod