skip to Main Content

I’m trying the following code: https://playcode.io/2047320

import React, { useState } from 'react';

export default function App() {
  const [example, setExample] = useState([]);

  const ButtonClick = () => {
    setExample([...example, { id: 'Hi', another: 12 }]);
  };

  return (
    <div className='App'>
      <button onClick={ButtonClick}>This is a button</button>
    </div>
  );
}

I know that in the playground it doesn’t show any errors however when I try the exact same code it spits out this error:

Type ‘{ id: string; another: number; }’ is not assignable to type
‘never’.ts(2322)

When I use setExample, I really don’t know why and it doesn’t seem to happen to anyone else.

I tried when initializing the array inside useState putting an example object which worked however now I need to grab these objects from a data base and there’s no obvious way to grab them while React knows it’s the same objects.

2

Answers


  1. const [example, setExample] = useState([]);
    

    Since you haven’t specified a type here, typescript needs to guess. It sees you initialized the state with an array, but has no idea what that array is supposed to contain, so it’s best guess is never[]. That’s not a particularly useful type though, since it’s impossible to add anything to a never[].

    Instead, you need to specify what kind of an array it is. useState is a generic, so you can provide the type in angle brackets:

    const [example, setExample] = useState<{ id: string; another: number; }[]>([]);
    
    Login or Signup to reply.
  2. The error you’re encountering is a common TypeScript issue when using useState with an empty array. When you initialize state with an empty array (useState([])), TypeScript cannot infer the type of the elements in the array. As a result, it defaults to never[], which means an array that can hold no values—not even null or undefined.

    Define an interface for your objects then, use this interface in your useState hook:

    import React, { useState } from 'react';
    
    interface ExampleItem {
      id: string;
      another: number;
    }
    
    export default function App() {
      const [example, setExample] = useState<ExampleItem[]>([]);
      const ButtonClick = () => {
        setExample([...example, { id: 'Hi', another: 12 }]);
      };
      return (
        <div className='App'>
          <button onClick={ButtonClick}>This is a button</button>
        </div>
      );
    }
    

    When fetching data from Firebase, you need to explicitly map the fetched data to your interface. Firebase returns data in a generic format, and TypeScript cannot automatically infer that it matches ExampleItem. Here’s how you can do it:

    import React, { useState, useEffect } from 'react';
    import { getDocs, collection } from 'firebase/firestore';
    import { db } from './firebaseConfig'; // Your Firebase configuration
    
    interface ExampleItem {
      id: string;
      another: number;
    }
    
    export default function App() {
      const [example, setExample] = useState<ExampleItem[]>([]);
    
      useEffect(() => {
        const fetchData = async () => {
          try {
            const querySnapshot = await getDocs(collection(db, 'yourCollectionName'));
            const data = querySnapshot.docs.map((doc) => {
              const docData = doc.data();
    
              const item: ExampleItem = {
                id: doc.id,
                another: docData.another as number,
              };
              return item;
            });
            setExample(data);
          } catch (error) {
            console.error('Error fetching data: ', error);
          }
        };
    
        fetchData();
      }, []);
    
      const ButtonClick = () => {
        setExample([...example, { id: 'Hi', another: 12 }]);
      };
    
      return (
        <div className='App'>
          <button onClick={ButtonClick}>This is a button</button>
          {example.map((item) => (
            <div key={item.id}>
              ID: {item.id}, Another: {item.another}
            </div>
          ))}
        </div>
      );
    }
    

    (I recommand to use an external function to map your records with the interface, avoid doing it in your useffect)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search