Why does passing valid types to a typed array constructor generate an error

huangapple go评论61阅读模式
英文:

Why does passing valid types to a typed array constructor generate an error

问题

你可以将一个数字、一个JavaScript本地数组或另一个类型化数组(以及其他内容)传递给类型化数组视图构造函数。

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

考虑到这一点,我希望这个 TypeScript 代码能够工作:

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

typescript playground

但它失败了,显示如下错误:

没有重载与此调用匹配。
最后一个重载引发了以下错误。
参数类型 'number | Int32Array | number[]' 不能分配给类型 'ArrayBufferLike'。
类型 'number' 不能分配给类型 'ArrayBufferLike'。(2769)

我做错了什么吗?这是已知的限制吗?

英文:

You can pass a number, an JavaScript native array, or another typedarray (and other things) to a typed array view constructor

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

given that, I'd expect this typescript to work

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

typescript playground

but it fails with

>
> 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)
>

Am I doing something wrong? Is this a known limitation?

答案1

得分: 1

TypeScript库为类型化数组构造函数(例如Int32Array构造函数,来源于lib.es5.d.tslib.es2015.iterable.d.tslib.es2017.typedarrays.d.ts)的类型声明是一系列重载的形式。也就是说,存在多个调用签名:

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;
}

当在TypeScript中调用重载函数(或者使用new来创建重载的构造函数)时,它会解析为一个调用签名。如果没有适用的单一调用签名,则调用将失败。类型检查器不会尝试合成组合调用签名,以接受各个调用签名接受的参数的联合。对于此类支持,有一个长期存在的问题,请参见microsoft/TypeScript#14107。在这个问题得到解决之前,您需要绕过它。

最简单的解决方法是使用类型断言

return new Int32Array(data as number); // 例如

如果您想要“修复” Int32Array,可以合并一个更宽松的调用签名(请记住,如果您在模块中而不是在环境范围内编写代码,则需要使用全局增强):

// 声明全局 { // 如果您在模块中,请使用这个
interface Int32ArrayConstructor {
  new(x?: number | Iterable<number> | ArrayBufferLike): Int32Array;
}
// }

然后,您的原始调用将可以正常工作。

Playground链接到代码

英文:

The TypeScript library typings for the typed array constructors (such as the Int32Array constructor, from lib.es5.d.ts, lib.es2015.iterable.d.ts, and lib.es2017.typedarrays.d.ts, each addition corresponding to changes in the language spec over time) are implemented as a series of overloads. That is, there are multiple call signatures:

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

And when you call an overloaded function (or new an overloaded constructor) in TypeScript, it resolves to exactly one call signature. If no single call signature is appropriate, the call fails. The type checker does not try to synthesize combined call signatures that would accept a union of the parameters accepted by individual call signatures. There is a longstanding open issue for this sort of support, at microsoft/TypeScript#14107. Until and unless that changes you'll need to work around it.


By far the easiest workaround here is to use a type assertion:

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

If you want to "fix" Int32Array you can merge in a more permissive call signature (remembering to use global augmentation if you're in a module and not writing in ambient scope):

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

And then your original call will work without issue.

Playground link to code

huangapple
  • 本文由 发表于 2023年8月4日 07:52:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76832217.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定