我想向 Array 类添加一些函数(我不希望将它们作为类的外部函数,因为理想情况下在对象后面键入 .
时可以发现它们)。这是我目前所拥有的:
export class List<T> extends Array<T> {
constructor(items?: Array<T>) {
super(...items)
Object.setPrototypeOf(this, List.prototype);
}
get first(): T {
return this[0]
}
}
这运行良好:
const list = new List([1,2,3]);
console.log(list.first)
但是如果我尝试运行这个:
const list = new List([1,2,3]);
console.log(list.map(x=>x*2))
我收到以下错误:
super(...items)
^
TypeError: Found non-callable @@iterator
理想情况下,我会得到一个等效于 new List(this.map(x=>x*2))
的对象。我如何扩展 Array 类而不必重写所有方法阵列?
最佳答案
我认为这里的问题是你的 List
构造函数不期望与 Array
相同的参数构造函数。
当像 map()
这样的内置方法时创建一个新数组,他们使用在 static Symbol.species
class property 中找到的构造函数构造它.默认情况下,这与类构造函数本身相同......除非您覆盖它。所以List[Symbol.species]
是List
.和 List.prototype.map()
最终会调用 new List(...)
.我很确定这些方法需要 [Symbol.species]
处的构造函数采取the same arguments as the Array
constructor ,即这些重载之一:
new Array(element0, element1[, ...[, elementN]]); // variadic arguments, one per item in array
new Array(arrayLength); // one numeric argument specifying length
但是你的List
构造函数期望处理它的第一个(也是唯一的)参数 items
作为可迭代对象(因为它在对 super(...items)
的调用中使用了 spread syntax。当 list.map(x=>x*2)
执行时,它会调用类似于 new List(3)
的内容,并且您会收到有关 3
不可迭代的错误消息。
那么,您能做些什么来解决这个问题呢?到目前为止,最简单的方法是确保您的 List
构造函数与 ArrayConstructor
兼容类型,让它采用相同的参数类型。
下一个最简单的事情是覆盖 List[Symbol.species]
并返回 Array
构造函数:
static get [Symbol.species](): ArrayConstructor {
return Array;
}
但这意味着 list.map(x => x*2)
返回 Array
而不是 List
.
假设您真的需要 List
构造函数采用单个可迭代参数而不是与 Array
相同的可变参数或可能是单个数字参数,并假设您需要 list.map()
返回 List
,您可以覆盖 List[Symbol.species]
属性更复杂:
static get [Symbol.species](): ArrayConstructor {
return Object.assign(function (...items: any[]) {
return new List(new Array(...items))
}, List) as any;
}
这实质上会导致 native 方法调用 new List(new Array(x,y,z))
而不是 new List(x,y,z)
.
好的,希望这有道理并能为您指明方向。祝你好运!
关于typescript - 如何扩展 Array 类并保留其实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54522949/