A spread argument must either have a tuple type or be passed to a rest parameter React

Viewed 41893

I have this code in Typescript:

const [history, setHistory] = useState([Array(9).fill(null)]);
const newHistory = history.slice(0, currentStep + 1);

and when I want to set new State using spread operators like that:

setHistory(...newHistory);

I have errors:

A spread argument must either have a tuple type or be passed to a rest parameter.

Can someone can help my, how I can properly types this?

4 Answers

In general, you can avoid such errors by using apply

setHistory(...newHistory); //drops error

setHistory.apply(null, newHistory) //works

but in your example there's a problem: you init history with [[null, null, null...]] then get it, slice to [[null, null, ...], ...] and try to set it back as setHistory([null, null], null).

it seems that you just need to use setHistory(newHistory);

To put this simply:

Because you're using the spread operator directly, you're passing in multiple arguments to your useState function, but useState functions only accept a single argument. Instead, use the spread operator to create a single array, and pass that in.

const newObject = [...newHistory];
setHistory(newObject);

// or, even simpler: 
setHistory([...newHistory]);

// NOT the below - this is passing in multiple arguments.
setHistory(...newHistory);

This worked for me perfectly!

setHistory(...(newHistory as []));

When using useState, index 1 in the tuple returned is setHistory. That should only accept one argument (the new value). The example in the original post is spreading the history into potentially 8 arguments. It needs to be passed as an array which can be as simple as setHistory(newHistory).

If the intention is to always modify the previous state, I would call setHistory(previousHistory => previousHistory.slice(x, y)).

Also! For Typescript, you need to declare a type for useState like this useState<History[]>(Array(9).fill(null)); Without declaring a type, typescript is going to infer something that, in this case, may not be what you want.

Just note, you don't always need to declare a type for useState. Actually, I'd encourage using type inference whenever possible. If the initial value is null or undefined, you won't be able to use type inference in Typescript.

Related