我试图通过将任意TypedArray作为输入来编写一个扩展/收缩TypedArray的函数,并返回一个具有不同大小的新的同型TypedArray并将原始元素复制到其中。
例如,当你通过新的new Uint32Array([1,2,3])
大小的5
时,它将返回new Uint32Array([1,2,3,0,0])
。
export const resize = <T>(
source: ArrayLike<T>, newSize: number,
): ArrayLike<T> => {
if (!source.length) { return new source.constructor(newSize); }
newSize = typeof newSize === "number" ? newSize : source.length;
if (newSize >= source.length) {
const buf = new ArrayBuffer(newSize * source.BYTES_PER_ELEMENT);
const arr = new source.constructor(buf);
arr.set(source);
return arr;
}
return source.slice(0, newSize);
};
虽然代码按预期工作,但TSC抱怨1)ArrayType没有BYTES_PER_ELEMENT
和slice
,以及2)Cannot use 'new' with an expression whose type lacks a call or construct signature
用于语句new source.constructor()
。
有没有办法为TSC了解我的意图的功能指定类型接口?
对于1),我理解ArrayLike没有为TypedArray定义的接口,但是单个类型的数组似乎不从公共类继承...例如,我可以使用const expand = (source: <Uint32Array|Uint16Array|...>): <Uint32Array|Uint16Array|...> => {}
而不是使用泛型。但它失去了返回类型的上下文是源数组的相同类型。
对于2)我对如何解决这个错误毫无头绪。 TSC似乎有理由抱怨源的构造函数缺少类型信息。但是如果我能为1)传递正确的类型,我认为2)也会消失。
ref)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
这不是beautitiful,但它的工作原理:
type TypedArray = ArrayLike<any> & {
BYTES_PER_ELEMENT: number;
set(array: ArrayLike<number>, offset?: number): void;
slice(start?: number, end?: number): TypedArray;
};
type TypedArrayConstructor<T> = {
new (): T;
new (buffer: ArrayBuffer): T;
BYTES_PER_ELEMENT: number;
}
export const resize = <T extends TypedArray>(source: T, newSize: number): T => {
if (!source.length) {
return new (source.constructor as TypedArrayConstructor<T>)();
}
newSize = typeof newSize === "number" ? newSize : source.length;
if (newSize >= source.length) {
const buf = new ArrayBuffer(newSize * source.BYTES_PER_ELEMENT);
const arr = new (source.constructor as TypedArrayConstructor<T>)(buf);
arr.set(source);
return arr;
}
return source.slice(0, newSize) as T;
};
(Qazxswpoi)
我抓住@Nitzan的答案并按摩它直到所有的类型演员都消失了,但不幸的是这个解决方案受到了code in playground的影响,似乎没有没有类型转换的解决方法。我发布代码以供将来参考。
警告:此代码自2017/05/16起未编译。
untyped constructor property issue here
您只需在声明文件中定义通用interface GenericTypedArray<T> extends ArrayLike<number> {
BYTES_PER_ELEMENT: number;
set(array: ArrayLike<number>, offset?: number): void;
slice(start?: number, end?: number): T;
constructor: GenericTypedArrayConstructor<T>;
}
interface GenericTypedArrayConstructor<T> {
new (): T;
new (buffer: ArrayBuffer): T;
}
export function resize<T extends GenericTypedArray<T>>(source: T, newSize: number): T {
if (!source.length) {
return new source.constructor();
}
newSize = typeof newSize === "number" ? newSize : source.length;
if (newSize >= source.length) {
const buf = new ArrayBuffer(newSize * source.BYTES_PER_ELEMENT);
const arr = new source.constructor(buf);
arr.set(source);
return arr;
}
return source.slice(0, newSize);
};
class DummyArray {
constructor();
constructor(buffer: ArrayBuffer);
constructor(array: ArrayLike<number>);
constructor(arg?) { }
// Hack to have a typed constructor property, see https://github.com/Microsoft/TypeScript/issues/3841
'constructor': typeof DummyArray;
BYTES_PER_ELEMENT: number;
length: number;
[index: number]: number;
set(array: ArrayLike<number>, offset?: number): void { }
slice(start?: number, end?: number): this { return this; }
static BYTES_PER_ELEMENT: number;
}
// How it intended to work
resize(new DummyArray([1, 2, 3]), 5);
// How it fails to typecheck
// Types of property 'constructor' are incompatible.
// Type 'Function' is not assignable to type 'GenericTypedArrayConstructor<Uint8Array>'.
resize(new Uint8Array([1, 2, 3]), 5);
即可。
1-在您的应用中创建名为TypedArray
的文件。
2-添加以下行:
extras.d.ts
然后通用type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
类型将在整个项目中可用。您可以使用此TypedArray
文件继续声明在整个应用程序中使用的更多自定义类型。