0

I'm trying to type an arrow function that gets a json file. The problem is that json returns me an object of objects.

I'm trying to make it so that I don't have to describe each object (because there may be several levels of nesting) and do it through the type:

  type Dictionary = {
    menu: Record<string, unknown>;
    pages: Record<string, unknown>;
    result: Record<string, unknown>;
  };

My function:

  const getData = async (lang: string): Promise<Dictionary> => {
    const path = `src/assets/file${lang}.json`;
    try {
      const response = await fetch(path);
      if (!response.ok) {
        throw new Error(`Some error`);
      }
      const data = await response.json();
      setDict(data.menu);
    } catch (error) {
      if (error) setError(error);
    }
  };
  useEffect(() => {
    getData(lang);
  }, []);

But I get errors: Unsafe assignment of an any value.

Unsafe argument of type any assigned to a parameter of type SetStateAction<null>

Unsafe member access .menu on an any value.

Argument of type '{}' is not assignable to parameter of type 'SetStateAction'.

Type '{}' provides no match for the signature '(prevState: null): null'.

Where to start to fix it? What did I missed?

Jhon
  • 37
  • 5
  • 2
    `fetch` can't be typed. The only thing you can do is to type check the response or just assign the correct type to it like in [here](https://www.typescriptlang.org/play?ts=5.0.4#code/C4TwDgpgBAIglgY2HA9gOwIYCcRQLxQDeAUFFALYRoCuAXFAEoQIpYAmAPAM7BZxoBzADRRqaANZoUAdzQA+ANykoYDAIhd6TFu269+w0RKmzFyrBuoAbYFuatOPPoJFjJM+UoC+S4hi4gaAhQABQAlPhyRMosaDxQGPgJ0hhwwFAAZhDACAAWIQDkBWG+ZLHxFlxg6FwQ9PBIqJg4SRgpaQkAdABWXOjh3kpAA) – wonderflame Jul 13 '23 at 11:03
  • 2
    Here's a thread about typing `fetch`: https://stackoverflow.com/questions/41103360/how-to-use-fetch-in-typescript – mbojko Jul 13 '23 at 11:03

1 Answers1

1

instead of getData function to set the state directly you can get it to return the data with explicit type annotations. something like this,

const getData = async (lang: string): Promise<Dictionary> => {
  try {
    ... all logics
    const data = await response.json();
    return {
      menu: data.menu as Record<string, unknown>,
      pages: data.pages as Record<string, unknown>,
      result: data.result as Record<string, unknown>,
    };
  } catch (error) {
    ... error handling
  }
}

then set the state from useEffect. like this,

useEffect(() => {
  getData(lang)
    .then((data) => {
      setDict(data.menu);
    })
    .catch((error) => {
      ..handle error
    })
}, [])

Or you can set it from the function if your prefer by creating the object first with correct type type annotations before calling the setter. In that case you will need to change the return type of your getData function to void i think. which ever you prefer.

Nazrul Chowdhury
  • 1,483
  • 1
  • 5
  • 11