开发者问题收集

函数参数类型中不存在属性“id”

2021-09-15
405

我编写了一个授权用户的调度,此调度返回以下类型之一:User 或 ResponseError

我的调度

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
      }
    }
  }

类型

export interface User {
  id?: number
}

export interface ErrorResponse {
  status: number
  errors: object
}

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

我在我的组件中调用此操作,如下所示:

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

redirect(res, 'dashboard')

请求后,我尝试检查请求中返回的内容(在重定向函数中):Error 或 User

const redirect = (res: User | ErrorResponse, redirectTo: string) => {
  if (res.id) {
    router.push({ name: redirectTo })
  } else {
    ElMessage.error('Oops, this is a error message.')
  }
}

但 TS 显示错误 属性“id”在类型“User | ErrorResponse”中不存在。属性“id”在类型“ErrorResponse”中不存在。

我理解为什么 TS 向我显示此错误,但我不明白如何修复它?

1个回答

问题是 res 可以是 User 接口,也可以是 ErrorResponse 接口,而 TypeScript 需要提示来消除歧义。有几种方法可以解决这个问题。

使用类型断言

一个快速的解决方法是使用带有 as 关键字的 类型断言

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

  } else {
    //...
  }
}

游乐场链接

这种方法的一个缺点是 res 的类型在 if 块内仍然是模棱两可的,因此仍然需要类型断言(或引用 resUser 类型的临时变量)来访问 User 特定的属性。

相反,我们可以使用 类型缩小 来增加类型安全性,如下所示。 注意:虽然 typeofinstanceof 类型保护是缩小类型的方法,但它们不能与接口或类型别名一起使用。

使用 in 类型保护

使用 in 运算符 检查其中一个类型中是否存在互斥属性,从而缩小到通过检查的类型。例如, idUser 是唯一的,因此请检查该属性是否在 in res 对象中:

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

  } else {
    //...
  }
}

Playground 链接

使用带有类型谓词的类型保护函数

使用带有 类型谓词 的函数来验证给定的对象是否为特定类型。由于 id 对于 User 是唯一的,因此该函数只需检查该属性是否为 undefined

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

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

  } else {
    //...
  }
}

游乐场链接

tony19
2021-09-16