Argument of type 'Promise<any>' is not assignable to parameter of type 'string'

Viewed 5486

Before initializing a React App, I fetch the user's info in the localStorage. Then, thanks to his id, I start a socket connection with the server.

When passing the user's id to the socket function, typescript claims that:

Argument of type 'Promise' is not assignable to parameter of type 'string'

Here is my index.tsx file:

const user = fetchUser();

if (user) {
  getNotifications(user);
}

ReactDOM.render(
      <App />,
  document.getElementById("root")
);

And the fetchUser() function:

export async function fetchUser() {
  try {
    if (!localStorage.getItem("MyAppName")) return null;
    const user = await jwt_decode(localStorage.MyAppName);
    updateUser(user);
    return user.id;
  } catch (err) {
    return null;
  }
}

How to fix this? If I remove the async/await it works, but performance-wise, is it ok to block the thread like this before initializing the app?

2 Answers

getUser is returning a promise as any function defined with async, which you are manipulating prior to its resolution. Because you're operating in a module global scope, you could do as follows, which would execute in non-blocking manner:


    getUser.then(user =>  {
       if(user) {
           getNotifications(user);
       }
    })
    .catch(e => console.log('Error: ', e))

I'm assuming that your App takes the notifications as a prop in some way. We want to load the notifications asynchronously and allow the App to render. Once the fetch is finished, the props for the App will change to include the notifications. Depending on what your app is expecting, you can either pass an empty array of notifications, or you can also add some prop which serves as a flag, like isLoadingNotifications, so that you can know to render a spinner within the app instead of the notifications.

This all should be done within a react component. Probably further down the tree, but for now lets just wrap your App inside an OuterApp.

interface Notification {
  /**... */
}

const OuterApp = () => {

  const [notifications, setNotifications] = useState<Notification[]>([]);

  const loadNotifications = async () => {
    await fetchUser();
    if ( user ) {
      const notes = await getNotifications( user );
      setNotifications( notes );
    }
  }

  useEffect( () => {
     loadNotifications();
    // should probably have a cleanup
  }, [] );

  return (
    <App 
      notifications={notifications}
    />
  )

}

ReactDOM.render(
  <OuterApp />,
  document.getElementById("root")
);
Related