1

Having trouble handling the response from an HTTP request using Axios with TypeScript. I don't understand the behavior I'm seeing. This returns the location once, and then when I refresh the page it doesn't work again, it says TypeError: Cannot read property 'location' of undefined I have a feeling I'm not understanding how this all works.

All I'm trying to do is get access all the data returned from the API. If anyone has simple examples of doing it with TypeScript I'd really appreciate it. I can do this in normal JavaScript, but having trouble translating it over to TypeScript. My problem is similar to this post

const Webmap: FC = () => {
  const url = 'https://data.police.uk/api/crimes-street/all-crime?lat=52.629729&lng=-1.131592&date=2019-10';

  interface User {
    id?: any;
    location?: any;
}

  const [users, setUserList] = useState<User[]>([]);
  useEffect(() => {
    axios.get<User[]>(url)
      .then(response => {
        // console.log(response.data);
        setUserList(response.data);
      });
  }, [])

   console.log(users[0].location)
franchyze923
  • 1,060
  • 2
  • 12
  • 38
  • 2
    Remember that all JavaScript is also valid TypeScript. If you had a working solution in JavaScript, that can also be used as a working solution in TypeScript. Therefore the problem in these cases is often some typo / copy-paste error. – Alex Walker Dec 15 '20 at 13:21
  • @AlexWalker Well the solution I was using in JavaScript didnt use Axios it used swr. I ran into a problem with this const fetcher = (...args) => fetch(...args).then(response => response.json()); TypeScript was complaining about Expected 1-2 arguments, but got 0 or more. TS2556 I couldn't figure out how to fix that error, so I was trying another solution. – franchyze923 Dec 15 '20 at 13:24

2 Answers2

2

What is users[0] before you populate the array with a call to setUserList? It's undefined. Maybe you should check that users[0] is non-nullish before you attempt to access its fields?

If it were me, I would not provide a default value to the useState call:

const [users, setUserList] = useState<User[]>();

which now means that the type of users will be User[] | undefined. Before the web request is made, the type of users will be undefined.

Now, when you want to use it, you can tell if it has been populated because checking that users is non-nullish

if(users != null){
    // users is definitely populated from the web request
    // although the array may contain no items
    users.forEach(u => console.log(u));
}

...or... in JSX/TSX

{users && users.map(u => (<div>{u.location}</div>)}

will narrow the type of users from User[] | undefined to User[].

You still need to ensure that the indexes that you explicitly access after this point, (e.g. users[0]) actually exist before you try to reference their properties.

spender
  • 117,338
  • 33
  • 229
  • 351
0

It is due to you trying to access the data even when it was not set in the state.

If users is not empty and truthy then log the data.

if(users && users.length > 0)){
    console.log(users.location)
}
yudhiesh
  • 6,383
  • 3
  • 16
  • 49
  • Your test will *always* pass and the error will persist. There is no point where `users` is not defined as an array. See the default value passed to `setState` above. – spender Dec 15 '20 at 13:16
  • Yes, I just tried adding that if statement and it still gives same error. – franchyze923 Dec 15 '20 at 13:19
  • Apologies as @spender pointed out you have an empty array at first. So I updated the answer to check if the array is empty or not then only `console.log()` the value. – yudhiesh Dec 15 '20 at 13:21