0

I have custom hook which pass parameter data with fetched data to component Settings. There I have hook setData11 in useEffect and I want to set in that hook data passed from useTable but I get error

Argument of type 'Data | Column[] | undefined' is not assignable to parameter of type 'SetStateAction<DataTable[] | undefined>'. Type 'Data' is not assignable to type 'SetStateAction<DataTable[] | undefined>'. Type 'Data' is missing the following properties from type 'DataTable[]': length, pop, push, concat, and 29 more.ts(2345)

interface DataTable {
  [id: string | number]: string | number;
}

interface Data {
  [category: string]: DataTable[];
}



const urls: string[] = [
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/comments",
  "https://jsonplaceholder.typicode.com/albums",
  "https://jsonplaceholder.typicode.com/photos",
  "https://jsonplaceholder.typicode.com/todos",
];

const useTable = (idurl: number, actualcategory: string) => {
  const [data, setData] = useState<Data>();

  const [columns, setColumns] = useState<Column[]>();
  const loadDatabase = () => {
    fetch(urls[idurl])
      .then((response) => response.json())
      .then((response) => {
        setData({
          ...data,
          new: response.filter((t: DataTable[], i: number) => {
            return i > 50 && i < 100 && t;
          }),

          removed: response.filter((t: DataTable[], i: number) => {
            return i > 100 && i < 150 && t;
          }),

          postponed: response.filter((t: DataTable[], i: number) => {
            return i > 50 && i < 100 && t;
          }),
        });

        const objcolumn: Column[] = Object.keys(response[0]).map(
          (t: string) => {
            let d: Column = { col: { title: t, disp: true } };
            return d;
          }
        );
        setColumns(objcolumn);
      });
  };
  useEffect(() => {
    loadDatabase();
    alert(JSON.stringify(data));
  }, []);
  return [data, columns];
};

export { useTable };






const Settings = () => { 
  const [data, columns, checkall, changeDatabase] = useTable(1, "new");  


const[ data1, setData1]=useState<DataTable[]>()
  useEffect(() => {
    setData1(data) 
  }, []);
 
return <></>
}
James Z
  • 12,209
  • 10
  • 24
  • 44
  • Does this answer your question? [Using Tuples in TypeScript (Type Inference)](https://stackoverflow.com/questions/48686849/using-tuples-in-typescript-type-inference) – Jared Smith Feb 19 '23 at 16:36
  • Your problem is your return type. If you have an array `["hi", 5]` and you do `arr[0]` it will have type `number | string`, not `string`. You can fix that by giving your hook an explicit return type or using `as const` as suggested by the existing answer. See the linked duplicate for more details. – Jared Smith Feb 19 '23 at 16:38
  • I've found out I have to use tuple or return [] as const – artur nowakowski Feb 19 '23 at 17:17

2 Answers2

1

It's not clear to me what this code is supposed to do, so it's difficult to give you a specific answer.

Your example contains several mistakes.

The first one can be confusing. When you return an array from your custom hook, its type will be inferred as Array<Data | Column[]>. If you want to get a signature similar to useState, you should use as const to tell TypeScript that this array contains a specific number of elements in a specific order and cannot change.

But even after you specify as const, TypeScript will complain about two things:

  1. The number of elements that you are trying to unpack from useTable should correspond to the two that you are returning (possibly just a typo). So it's should be const [data, columns] = useTable(...)
  2. The type Data | undefined and DataTable[] | undefined are incompatible, which is entirely true. I'm not entirely sure what your end goal is. If you want to use a specific category as the data1 state, you should pass some attribute of data
const useTable = (idurl: number, actualcategory: string) => {
  ...
  return [data, columns] as const; // use "as const"
};

// --------------

const Settings = () => { 
  // Remove extra parameters
  const [data, columns] = useTable(1, "new");  


  const [data1, setData1] = useState<DataTable[]>()

  useEffect(() => {
    // data also can be undefined, so you need to use ?. syntax
    setData1(data?.SOME_CATEGORY) 
  }, []);
 
  return <></>
}
Flat Globe
  • 173
  • 1
  • 6
  • 1
    I would also suggest OP use an empty array as the default value, which will simplify the union type by removing `undefined`. – Jared Smith Feb 19 '23 at 16:39
0

thanks for answer :)

here is resolution of the problem

https://fettblog.eu/typescript-react-typeing-custom-hooks/