I'm using TypeScript and I want to extend Array to enforce a specific argument. This way, I can make sure that whenever I create a FruitArray, the first element is a fruit.
So I tried extending Array in a class:
class FruitArray extends Array {
constructor(fruit: FruitsEnum, ...args: string[]) {
if (!enumContains(FruitsEnum, fruit)) {
throw new Error('Must initialize with a fruit!');
}
super(fruit, ...args);
}
}
However, the linter complains:
A spread argument must either have a tuple type or be passed to a rest parameter.
I think I am handling super() wrong, but I don't understand how to get it to work.
First I'll address the problem you asked about, but then point out a couple of things that may bite you with the approach of extending
Array.Re the specific error, it looks like the problem is that you've extended
Arraywithout specifying its element type. With the error (playground):Specifying an element type makes the error go away, for example here I'm giving
FruitsEnum | string(playground):Separately, though, a couple of issues with extending
Arraylike this:Your code isn't handling all of the construction signatures it has to handle to properly subclass
Array. It needs to support at least these:(I don't think it needs to support zero arguments. In the JavaScript specification, when creating arrays it does so via
ArrayCreateandArraySpeciesCreate, both of which expect alengthargument. But double-check me before relying on that.)TypeScript doesn't complain about not handling that first argument being a number (because overlaying types on JavaScript's
Arrayafter the fact is hard), but yourfruitparameter's value may well be a number. Example on the playground:While you can ensure that
FruitArraystarts out with aFruitsEnumvalue as its first element, that can soon become untrue (playground):There,
fis still aFruitArray, but the first element is now a string, not aFruitsEnum.You may be better off defining a tuple type or your own class that doesn't directly extend
Array(it could use an array in its implementation), but it depends on what you're going to do with it.