Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用于所有数值数组类型的TypeScript函数_Javascript_Arrays_Typescript_Generics_Constraints - Fatal编程技术网

Javascript 用于所有数值数组类型的TypeScript函数

Javascript 用于所有数值数组类型的TypeScript函数,javascript,arrays,typescript,generics,constraints,Javascript,Arrays,Typescript,Generics,Constraints,我正在尝试编写一个适用于所有JavaScript数组类型的函数,例如,在number[]、Float32Array等上。它应该返回作为参数得到的相同类型。一个简单的例子是: function addOne<T>(a: T) : T { return a.map((x: number) => x + 1); } function doSomethingWithArray(a, func) { return func(a); } 但我明白了 TS2322: Type '

我正在尝试编写一个适用于所有JavaScript数组类型的函数,例如,在
number[]
Float32Array
等上。它应该返回作为参数得到的相同类型。一个简单的例子是:

function addOne<T>(a: T) : T {
  return a.map((x: number) => x + 1);
}
function doSomethingWithArray(a, func) {
  return func(a);
}
但我明白了

TS2322: Type 'number[] | Float32Array' is not assignable to type 'NumberArray<T>'.   Type 'number[]' is not assignable to type 'NumberArray<T>'.
a
的类型应定义使用
func
的哪个签名。
我在JS中运行这个没有问题,但是当尝试添加正确的TS类型时,TS编译器会抱怨(我使用
“strict”:true
编译器选项运行)。

您的最后一个问题有一个简单的解决方案

函数应用(a:T,func:(x:T)=>U:U{
返回函数(a);
}

更新

这似乎奏效了,我看不出它有什么不安全之处

类型NumberArray=
{map:(f:(x:number)=>number)=>any}
&阵列状
&可移植的;
函数addOne(a:T):T{
返回a.map((x:number)=>x+1)
}
我不认为用
number[]
Float32Array
可以做你想做的事情,因为Javascript中没有Float32类型,我们也不能在Typescript中表达类似“我想要一个通用的
包装器
围绕一个类型
number | Float32 |……
”的东西。如果没有这两个特性,我不知道该怎么做

我们可以做一些让Typescript高兴的事情:

类型numberraray=
{
地图:功能
//在那里定义其他方法
}
&阵列状
&可移植的;
函数addOne(a:T):T{
返回a.map((x:number)=>x+1)
}
但它允许您将映射到除数字以外的类型:

函数addOne(a:T):T{
返回a.map((x:number):string=>x+'!')//woops
}
我们可以做到以下几点:

类型numberraray=
{
地图:(f:(x:number)=>number)=>NumberArray
//在那里定义其他方法
}
&阵列状
&可移植的;
函数addOne(a:T):T{
返回a.map((x:number)=>x+1)
}
但是我们会得到一个错误

Type 'NumberArray' is not assignable to type 'T'.
  'NumberArray' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ map: (f: (x: number) => number) => NumberArray; } & ArrayLike<number> & Iterable<number>

另一方面,我不认为创建一个只能处理类似数组的对象的
addOne
函数有什么价值。这是非常具体的。
map
的全部要点是将数据结构与转换分离

以下内容更灵活,因为
addOne
不需要知道它将在何处使用,并且类型信息将被保留:

constaddone=(x:number)=>x+1;
加一(3);
[1,2,3].地图(addOne);
Float32Array.from([1,2,3]).map(addOne);

不过,这并不能解决您的问题:一旦我们定义了一个需要接受
NumberArray
作为参数的函数,我们就回到了开始的地方…

类型脚本没有内置的
NumericArray
类型,其中
数组
Float32Array
等都是允许您访问所有属性的子类型常用方法。我也想不到一个一两行的解决方案能给你这个。相反,如果你真的需要这个,我建议你创建自己的类型。例如:

interface NumericArray {
  every(predicate: (value: number, index: number, array: this) => unknown, thisArg?: any): boolean;
  fill(value: number, start?: number, end?: number): this;
  filter(predicate: (value: number, index: number, array: this) => any, thisArg?: any): this;
  find(predicate: (value: number, index: number, obj: this) => boolean, thisArg?: any): number | undefined;
  findIndex(predicate: (value: number, index: number, obj: this) => boolean, thisArg?: any): number;
  forEach(callbackfn: (value: number, index: number, array: this) => void, thisArg?: any): void;
  indexOf(searchElement: number, fromIndex?: number): number;
  join(separator?: string): string;
  lastIndexOf(searchElement: number, fromIndex?: number): number;
  readonly length: number;
  map(callbackfn: (value: number, index: number, array: this) => number, thisArg?: any): this;
  reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: this) => number): number;
  reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: this) => number, initialValue: number): number;
  reduce<U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: this) => U, initialValue: U): U;
  reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: this) => number): number;
  reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: this) => number, initialValue: number): number;
  reduceRight<U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: this) => U, initialValue: U): U;
  reverse(): this;
  slice(start?: number, end?: number): this;
  some(predicate: (value: number, index: number, array: this) => unknown, thisArg?: any): boolean;
  sort(compareFn?: (a: number, b: number) => number): this;
  toLocaleString(): string;
  toString(): string;
  [index: number]: number;
}
您可以验证它是否能按预期在
Array
Float32Array
中工作:

function addOne<T extends NumericArray>(a: T): T {
  return a.map((x: number) => x + 1);
}
const arr = addOne([1, 2, 3]);
// const arr: number[]
console.log(arr); // [2, 3, 4];
arr.unshift(1); // okay

const float32Arr = addOne(new Float32Array([1, 2, 3]));
// const float32Arr: this
console.log(float32Arr) // this: {0: 2, 1: 3, 2: 4}
console.log(float32Arr.buffer.byteLength); // 12

您的
doSomethingWithArray
将如下所示:

function doSomethingWithArray<T extends NumericArray, R>(a: T, func: (a: T) => R) {
  return func(a);
}
console.log(doSomethingWithArray([4, 5, 6], x => x.unshift(3))); // 4
console.log(doSomethingWithArray(new Int8Array([1, 2, 3, 4, 5]), x => x.byteLength)); // 5
函数doSomethingWithArray(a:T,func:(a:T)=>R){
返回函数(a);
}
log(doSomethingWithArray([4,5,6],x=>x.unshift(3));//4.
log(doSomethingWithArray(新的Int8Array([1,2,3,4,5]),x=>x.bytellength));//5.
看起来不错


我肯定我遗漏了什么,但为什么不用重载签名来解决这个问题呢?重载什么?你能解释一下吗,最好是用一个游乐场链接?这个
技巧非常好。实际上,这是我第一次想在类型上使用接口。@jcalz。我现在意识到,传递函数的最后一个要求不会以这种方式工作。@porst17我不知道,可能是
filter(()=>false)
?这超出了原始问题的范围,因此我不确定评论部分是否是讨论此问题的最佳场所。但我的猜测是,处理
NumericArray
的函数将需要要求调用方传入您需要的任何内容,例如生成正确类型的新数组的构造函数。。。也许像。
addOne
只是一个简单的例子来说明函数签名。该函数应该能够使用OP中所述的所有数组方法,而不仅仅是map。事实上,我正在处理非平凡的数值算法,但这不是问题的重点。我的答案只是jcalz的一个不那么详尽、不那么优雅的版本,但它是完全相同的想法。至于你的意图,你的问题很清楚,但你的例子误导了我。
function doSomethingWithArray<T extends NumericArray, R>(a: T, func: (a: T) => R) {
  return func(a);
}
console.log(doSomethingWithArray([4, 5, 6], x => x.unshift(3))); // 4
console.log(doSomethingWithArray(new Int8Array([1, 2, 3, 4, 5]), x => x.byteLength)); // 5