What is the best way to set up a variable in Typescript that will be assigned the value of an asynchronous request once it is completed?

As a newcomer to typescript, I encountered an issue that hadn't occurred in my previous project. It appears that declaring a variable before an API request inside a try-catch block leads to typescript errors when attempting to use this variable after the try-catch.

Below, you'll find some sample code showcasing this problem.

The problematic variable is res, placed at the top within the if statement.

  interface AuthApiData {
      message: string;
      success: boolean;
    }

    interface AuthApiRes {
      status: number;
      data: AuthApiData;
    }

    if (router.pathname !== '/login') {
      let res: AuthApiRes;
      
      let status;
      const authenticate = async () => {
        try {
          res = await axiosPrivate.get('/api/gilat');
          status = res?.status;
        } catch (err) {
          console.log('authflow err:', err);
        }
      };

      authenticate();

      if (status === 200 && res?.data?.success === true) {
        // Code continuation intended here
      }
    }

To see the specific TypeScript errors and the tooltip displaying the error, refer to the image included below the question.

This code essentially declares a variable res before a try-catch block and attempts to utilize it in an if-statement afterward. Inside the try-catch, there's an API request assigning the result to this res variable upon resolving asynchronously.

If I assign an initial object matching its interface to res, the error disappears — for example, res = { status: 403, data: ... }.

I also tested initializing its type with:

let res = AuthApiRes | undefined

Although this resolves the issue, I'm uncertain whether it's considered "cheating" within TypeScript standards.

My goal isn't to assign this variable as an empty placeholder object but rather keep it unassigned until the API response is received.

Is this feasible? If not, how can I eliminate this error without initializing the variable or using a union type of undefined during its declaration?

https://i.sstatic.net/C6PRk.png

Answer №1

I attempted setting its type like this:

let res: AuthApiRes | undefined

This solution resolved the issue, but I feel it's untidy and maybe considered a workaround in TypeScript.

When a variable is declared without initialization, it defaults to undefined, which is why TypeScript doesn't raise an error when you include undefined in the union type.

In my opinion, the cleaner approach is to initialize res with null and then perform a null check:


let res: AuthApiRes | null = null;

if(res) {
  if(status === 200 && res.data?.success === true) {
    ...
  }
}

The same logic applies to the status variable.

If you're not fond of this method, you can use the non-null assertion operator with res:

let res!: AuthApiRes

This tells TypeScript that you will indeed assign a value to res, although it removes TypeScript's type checks, which, in my view, isn't worthwhile.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular button for opening or closing the menu that redirects the page to a localhost URL

I have implemented a template from the link below into my project. So far, everything has been working fine, but recently I noticed that the menu open/close button is malfunctioning. Whenever I click on the close button while on any page (for example, http ...

Out of nowhere, encountering TS2322 Typescript errors, causing type mismatches during the compilation phase

I am facing an issue with AWS Codebuild while deploying APIs written in lambda and exposed via API Gateway using Koa. The build process is throwing an error related to type assignment. src/components/chart-color-settings/chart-color-settings.ts(11,13): err ...

The parameter must be of type 'string', but you are attempting to assign a 'Promise<any>'

Starting a React App requires fetching the user's information from localStorage and initiating a socket connection with the server based on the user's id. However, when trying to pass the user's id to the socket function, TypeScript throws ...

The 'checked' property cannot be bound to 'mat-button-toggle' as it is not recognized as a valid property in Angular 9

I am encountering an issue with my Angular 9 application. I have integrated angular-material and imported the MatCheckboxModule correctly in the module. Here is the version of the material package I am using: "@angular/material": "^10.2.0&q ...

retrieve data types from an array of object values

I am looking to extract types from an array of objects. const names = [ { name: 'Bob' }, { name: 'Jane' }, { name: 'John' }, { name: 'Mike' }, ] The desired result should resemble thi ...

What steps can I take to allow a third-party JavaScript to access my TypeScript object?

I am working on an Angular application and I have a requirement to develop an API for a third-party JavaScript that will be injected dynamically. public class MyApi{ public callSomeFunction():void{...} public getSomeValue():any {...} } var publicA ...

What is the best approach to limit the return type of a function in JSX?

Is it possible to create a function where the return type should be a specific JSX type? For instance: const setHosting : <GitlabLogo> | <GithubLogo> = (h: Hosting) => ??? In this case, the return type must either be <GitlabLogo> or ...

Expanding the property of an established type to a nested type

Let's talk about titles. Well, maybe not this one. I tried to come up with a good title, but it didn't work out as planned. In my coding journey, I have created a cool interface called DefaultTheme: export interface DefaultTheme { colors: ...

New Entry failing to appear in table after new record is inserted in CRUD Angular application

Working with Angular 13, I developed a basic CRUD application for managing employee data. Upon submitting new information, the createEmployee() service is executed and the data is displayed in the console. However, sometimes the newly created entry does no ...

Angular: Incorporating a custom validation function into the controller - Techniques for accessing the 'this' keyword

I'm currently working on implementing a custom validator for a form in Angular. I've encountered an issue where I am unable to access the controller's this within the validator function. This is the validator function that's causing tr ...

Exploring ways to conduct a thorough scan of object values, inclusive of nested arrays

My goal is to extract all values from an object. This object also includes arrays, and those arrays contain objects that in turn can have arrays. function iterate(obj) { Object.keys(obj).forEach(key => { console.log(`key: ${key}, value: ${o ...

Angular encountered an error when trying to access the property "fruits" of an undefined object

When working with Angular, I encountered an issue where I received the error message "cannot read property 'fruits' of undefined." Within my class definition, I have included the following: export class MyClass implements OnInit { fruits: any[] ...

Is there a Typescript function error that occurs when attempting to rename a key, stating it "could potentially be instantiated with a different subtype"?

I am currently working on a Mongoify type that accepts a type T, removes the id key, and replaces it with an _id key. type Mongoify<T extends {id: string}> = Omit<T, "id"> & { _id: ObjectId }; function fromMongo<T extends ...

What is the best way to arrange this script?

I am currently working on a Javascript script that automatically scrolls down and loads a new URL when it reaches the bottom of the page. However, I would like to add a delay of 30 seconds before the new URL is loaded. Although I am relatively new to Java ...

Utilizing Javascript to load and parse data retrieved from an HTTP request

Within my application, a server with a rest interface is utilized to manage all database entries. Upon user login, the objective is to load and map all user data from database models to usable models. A key distinction between the two is that database mode ...

What is the best way to implement global error handling for NextJS API requests?

Is there a method to set up a Global error handler that captures the stack trace of errors and sends it to an external system like NewRelic without needing to modify each individual API? This would follow the DRY principle by avoiding changes to multiple ...

Issue: The function (0, react__WEBPACK_IMPORTED_MODULE_1__.useActionState) is not recognized as a valid function or its output is not iterable

I found a great example of using useActionState at this source. Currently, I am implementing it in my project with Next.js and TypeScript. app/page.tsx: "use client"; import { useActionState } from "react"; import { createUser } from ...

React 16 exhibiting unexpected behavior with class names

I am trying to implement the classnames object into my input field within a react 16 project, completely independent of the webpack tool. const fieldClassName = classnames( formControlStyles.field, 'form-control' ) The 'form-control& ...

Having trouble with routerLink in your custom library while using Angular 4?

In my Angular 4 project, I have developed a custom sidebar library and integrated it into the main project. My current issue is that I want to provide the option for users to "open in new tab/window" from the browser's context menu without having the ...

Managing errors with Angular2 Observables within the HTML template

The updated Angular's use of observables is a game-changer. No more long chains of .done().fail().always() like in JQuery - NG2 simplifies it all with the | async pipe. However, what happens if something goes wrong while loading data for myObservable? ...