The function argument does not have the property 'id'

I created a function that authorizes a user, which can return either a User object or a ResponseError

Here is my function:

async loginUser ({ commit }, data) {
    try {
      const user = await loginUser(data)
      commit('setUser', user)
      return user
    } catch (e) {
      return {
        status: e.response.status,
        errors: e.response.data.errors
      }
    }
  }

Defined Types:

export interface User {
  id?: number
}

export interface ErrorResponse {
  status: number
  errors: object
}

export interface Actions {
  loginUser({ commit }: { commit: Commit }, data: LoginData): Promise<User | ErrorResponse>
}

And I use this function in my component as follows:

const res = await this.$store.dispatch('loginUser', {
   email: this.formData.email,
   password: this.formData.password
})

redirect(res, 'dashboard')

After the request, I need to check if an Error or User was returned (in the redirect function):

const redirect = (res: User | ErrorResponse, redirectTo: string) => {
  if (res.id) {
    router.push({ name: redirectTo })
  } else {
    ElMessage.error('Oops, there was an error.')
  }
}

However, TypeScript shows me an error stating:

 Property 'id' does not exist on type 'User | ErrorResponse'.Property 'id' does not exist on type 'ErrorResponse'.

I understand why this error occurs, but I'm unsure how to fix it. Any suggestions?

Answer №1

One issue arises when res can be either the User interface or the ErrorResponse interface, requiring a hint for TypeScript to differentiate between the two. Various solutions exist to address this dilemma.

Implementing Type Assertion

An immediate remedy involves utilizing type assertion with the as keyword:

const redirect = (res: User | ErrorResponse, redirectTo: string) => {
  if ((res as User).id) {
    // res represents User or ErrorResponse
    console.log('User ID', (res as User).id)

  } else {
    //...
  }
}

Playground Link

However, this approach still leaves the type of res ambiguous within the if-block, necessitating further type assertions or temporary variables referencing res as type User to access properties specific to User.

Alternatively, employing type narrowing enhances type safety, as outlined below. Note: Although typeof or instanceof type guards can narrow types, they do not apply to interfaces or type aliases.

Utilize an in Type Guard

The use of the in operator verifies the existence of a distinct property in one of the types, thereby refining the type that meets the criteria. For instance, since id is exclusive to User, confirming the presence of this property in the res object indicates its status as a User:

const redirect = (res: User | ErrorResponse, redirectTo: string) => {
  if ('id' in res && res.id) {
    // res represents User
    console.log('User ID', res.id)

  } else {
    //...
  }
}

Playground Link

Employ a Type Guard Function with a Type Predicate

Creating a function with a type predicate confirms whether the provided object corresponds to a particular type. Given that id solely belongs to User, the function simply checks for the absence of undefined in the property:

const isUser = (obj: any): obj is User => (obj as User).id !== undefined

const redirect = (res: User | ErrorResponse, redirectTo: string) => {
  if (isUser(res)) {
    // res represents User
    console.log('User ID', res.id)

  } else {
    //...
  }
}

Playground Link

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

Unable to utilize a single file component. "Enrolled but never implemented"

I am having trouble importing a single file component called zoomOnHover into my Product.vue component. Whenever I try to include it, I get an error saying: "zoomOnHover is assigned a value but never used". I am using vue-cli and wondering if this issue h ...

The Directus API and application will be running on the same server as the front-end interface

Currently, I am in the process of building a small website using Directus as my backend system. Directus offers a user-friendly interface for managing databases, making it a great fit for my project. I plan to code the front end using VueJS and want both c ...

An error occurred with the datepicker: Unable to connect to 'bsValue' as it is not recognized as a property of 'input'

Despite importing DatepickerModule.forRoot() in my Angular unit test, I am encountering the following error: Error: Template parse errors: Can't bind to 'bsConfig' since it isn't a known property of 'input'. (" ...

Encountered an issue while trying to install the package '@angular/cli'

Encountered errors while attempting to install @angular/cli using npm install -g @angular/cli. The node and npm versions on my system are as follows: C:\WINDOWS\system32>node -v v 12.4.0 C:\WINDOWS\system32>npm -v 'C ...

Only the final defined document is instantiated by the Swagger-ui-express module

Currently, I am working on a Typescripted nodejs server and facing an issue with defining different swagger paths for separated controllers. The problem is that the swagger-ui-express module only displays the last defined document in the specific route. I ...

Modify animation trigger when mouse hovers over

I am looking to create a feature where a slide overlay appears from the bottom of a thumbnail when the user hovers over it, and retracts when the user is not hovering. animations: [ trigger('overlaySlide', [ state(&ap ...

Surprising Discovery: TypeScript - node_modules Found in Unusual Directory

Is there a way to make TypeScript imports function properly even if the node_modules directory is not directly in the tree? How can I prevent TypeScript from throwing errors when importing something like rxjs from external/node_modules. For Example: Dir ...

Can a type be established that references a type parameter from a different line?

Exploring the Promise type with an illustration: interface Promise<T> { then<TResult1 = T, TResult2 = never>( onfulfilled?: | ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ...

Fundamentals of Angular 2

It's not just an inconvenience, but something that truly frustrates me. Could someone please clarify the following: Why does Angular load these scripts in HTML directly from node_modules https://i.sstatic.net/D8UrG.png Why am I unable to simply imp ...

What's stopping me from installing the npm stripe checkout package?

After running the command npm install vue-stripe-checkout, I encountered the following error: vue.runtime.esm.js?2b0e:5106 Uncaught TypeError: Cannot read property 'install' of undefined at Function.Vue.use (vue.runtime.esm.js?2b0e:5106) at eval ...

Vuejs has the capability of sending data even after the page or browser has been

When you close a tab or browser, it is necessary to send the form data to Vue. This can be achieved through the mounted or created methods using window.addEventListener("beforeunload", this.unload). Unfortunately, I encountered an issue where the ...

Issues arise when attempting to extract data from a data provider using JSON within the context of the Ionic framework

Hey there! I'm relatively new to the world of Angular and Ionic, and I've embarked on a project to create a pokedex app. My approach involves using a JSON file containing an array of "pocket monsters". However, my current challenge lies in extrac ...

Using Angular's ElementRef to set focus on an ion-textarea: "The 'setFocus' property is not found on the 'ElementRef' type."

After developing a textarea component that automatically focuses itself when created using the ngAfterViewInit() method, everything seemed to be working perfectly as expected. ngAfterViewInit() { if(this.text.length===0){ this.theinput.setFocus(); ...

The Vue component functions properly after undergoing the Hot Reload process

Spent countless hours searching online for a solution, but to no avail (plus an explanation). I am encountering an issue with my Vue select component that is connected to a Datatable: <select @change="statusChanged()" v-model="active" name="Fi ...

Transforming FormData string key names into a Json Object that is easily accessible

Recently, I encountered an issue where my frontend (JS) was sending a request to my backend (Node Typescript) using FormData, which included images. Here is an example of how the data was being sent: https://i.stack.imgur.com/5uARo.png Upon logging the r ...

Is React 18 compatible with both react-redux and react-router?

At present, my react application is running on the following versions: react 17.0.x react-dom 17.0.x react-redux 7.2.x react-router-dom 5.x.x react-scripts 4.0.x redux 4.x.x My initial step towards upgrading to react@18 involved updating react-scripts to ...

Ways to access an Environment variable within VueJs components

Seeking assistance from anyone. I'm trying to figure out how to access an environment variable that's stored in the .env file of a Laravel project from within a vuejs component. .env file SECREAT_KEY=<My secreat key here> I need to retr ...

Leveraging $refs in Element UI's input component

Is there a way to utilize the ref attribute with the el-input component in Element-UI? My goal is to focus on the input field when my Vue instance is mounted. Below is the snippet of code I have been working with: <div id="app"> <el-input typ ...

Enhancing Responses in NestJS with External API Data

I'm a beginner in NestJs, Graphql, and typescript. I am trying to make an external API call that is essentially a Graphql query itself. The goal is to modify the response, if necessary, and then return it for the original request or query, in this ca ...

Error TS2322: The specified type 'Element' cannot be assigned to the type 'boolean'

I'm just beginning to explore TypeScript and I ran into an issue while trying to type my constant dialogFuncMap. I received an error (listed in the comments below). Why am I getting this error if the type of state is boolean? And how can I resolve it ...