franchyze923
franchyze923

Reputation: 1200

Getting Typescript error: Type 'any[]' is not assignable to type 'never[]'. TS2345

I'm not sure why I'm getting this error. Type 'any[]' is not assignable to type 'never[]'. TS2345 Here is my code. It's complaining about the merged array.

  const [allInfo, setAllInfo] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const validatorResponse = await axios.get(validatorEndpoint);
      const validatorIps = [];
      for (let i = 0; i < validatorResponse.data.count; i += 1) {
        const ipAddress = validatorResponse.data.results[i].ip_address;
        validatorIps.push({query: ipAddress});
      }
      const resultBatch = await axios.post(ipInfoEndpoint, validatorIps);
      const merged = [];
      for (let i = 0; i < validatorResponse.data.results.length; i += 1) {
        merged.push({
          ...validatorResponse.data.results[i],
          ...resultBatch.data[i],
        });
      }
      console.log(merged);
      setAllInfo(merged);
    }
    fetchData();
  }, []);

This is the line returning the error -

setAllInfo(merged);

I've tried

const result : string[] = [];

As well as const

[allInfo, setAllInfo] = useState([] as any);

Upvotes: 1

Views: 1342

Answers (3)

Cory Harper
Cory Harper

Reputation: 1055

Giving your state an interface to strictly type it is a common pattern when using Typescript and React, otherwise the Typescript compiler will infer it. While with many other types inference will work, with an array most of the time it won't because the safest type to assume for an empty array is never[].

All of that to say that when you are creating an array that is assigned to a variable it is best to type that array strictly using an interface or custom type.

https://www.typescriptlang.org/docs/handbook/interfaces.html

So your code will often look more like this:

interface Foo {
  ...
}
...

const [allInfo, setAllInfo] = useState<Foo[]>([]);

const fetchData = async (): Promise<void> => {
  const { 
    data: {
     results = []
    } = {} 
  } = await axios.get(validatorEndpoint);
  const validatorIps = results.map(({ ip_address }) => ({query: id_address}));
  const { data = [] } = await axios.post(ipInfoEndpoint, validatorIps);

  const merged = results.map((result, i) => ({
    ...result,
    ...data[i]
  });

 setAllInfo(merged)
}

useEffect(() => {
  fetchData();
}, []);

I typed that using what information I had, but in the future you should also give types to your API responses inside of fetchData or you'll run into more type issues by relying on inference.

One last thing, fetchData inside of the useEffect is violating exhaustive-deps linter rule React has. It isn't hugely problematic in this case, but fetchData should really be defined inside the useEffect or with the useCallback hook.

Upvotes: 1

Edward Sanchez
Edward Sanchez

Reputation: 29

use default values this prevent future TypeError, try to use real typed, not use any like type

const [allInfo, setAllInfo] = useState<Array<typed>>([]);

const fetchData = async (): Promise<void> => {
  const { 
    data: {
     results = []
    } = {} 
  } = await axios.get(validatorEndpoint);
  const validatorIps = results.map(({ ip_address}) => ({query: id_address}));

  const { data = []}= await axios.post(ipInfoEndpoint, validatorIps);
  const merged = results.map((result, i) => ({
    ...result,
    ...data[i]
  });
 setAllInfo(merged)
}

useEffect(() => {
  fetchData();
}, []);

`

Upvotes: 0

Omri Luzon
Omri Luzon

Reputation: 4214

You can fix the error be giving merged a better type than the inferred one (never[]).

const merged: any[] = []; should be enough, but I would recommend you consider a better type.

You can also help typescript infer the type by using the Array.prototype.map method, and it's generally better to use .map when you want to create new array with every element transformed from the original array.

const merged = validatorResponse.data.results.map((result, i) => ({
   ...result,
   ...resultBatch.data[i],
})

Upvotes: 0

Related Questions