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.
2
Answers
Why do you need to extend Array? can’t you use something like this?
for the class implementation:
Why does fruits array have 2 types?
string
andFruitsEnum
? Why dont you just use FruitsEnum If you are going to enforce FruitsEnum type?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
Array
without 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
Array
like 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
ArrayCreate
andArraySpeciesCreate
, both of which expect alength
argument. 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
Array
after the fact is hard), but yourfruit
parameter’s value may well be a number. Example on the playground:While you can ensure that
FruitArray
starts out with aFruitsEnum
value as its first element, that can soon become untrue (playground):There,
f
is 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.