首页 > 解决方案 > TypeScript 参数类型是多种类型的联合:如何确定提供了哪些类型并使用它?

问题描述

我正在使用 TypeScript 中的React Google Login库。它具有 TypeScript 的类型绑定,但所有示例都使用 JavaScript,而且我对 TypeScript 还是很陌生。

设置代码如下所示:

  <GoogleLogin
    clientId="client-id-value"
    onSuccess={successResponseGoogle}
    onFailure={failureResponseGoogle}
    cookiePolicy={'single_host_origin'}
  />

在 TypeScript 中,onSuccess 回调的签名是:

readonly onSuccess: (response: GoogleLoginResponse | GoogleLoginResponseOffline) => void

GoogleLoginResponseOffline类型只有一个属性 ,code其中GoogleLoginResponse有一系列属性可以访问经过身份验证的用户的详细信息。

我遇到的问题是 TypeScript 不允许我访问响应参数上的任何 GoogleLoginResponse 属性,例如

“类型 GoogleLoginResponseOffline 上不存在属性 'getBasicProfile'”

我尝试了以下方法来强制转换或检查参数的类型,但都给出了一种或另一种类型的错误。我的功能如下所示:

const responseGoogleSuccess = (response: GoogleLoginResponse|GoogleLoginResponseOffline) => {

  // Tried to check for property to identify type
  if(response.googleId){    // Property 'googleId' does not exist on type 'GoogleLoginResponseOffline'
      const profile = response.getBasicProfile();  // Property 'getBasicProfile' does not exist on type 'GoogleLoginResponseOffline'
  }

  // Tried to cast like this
  const typedResponse = <GoogleLoginResponse>response;

  // Tried to check type
  if(response instanceof GoogleLoginResponse){   // 'GoogleLoginResponse' only refers to a type, but is being used as a value here.
  }
}

它从TypeScript 文档中看起来好像if(response instanceof GoogleLoginResponse)很接近,在这种情况下失败,因为GoogleLoginResponse它是一个接口并且它需要是一个类。

请告诉我这是怎么做到的!我查看了很多标题相似的 StackOverflow 问题,但没有一个涵盖这一点。

标签: reactjstypescripttypeguards

解决方案


您可以使用in运算符来缩小类型

对于n in x表达式,其中n是字符串文字或字符串文字类型并且x是联合类型,“真”分支缩小到具有可选或必需属性的类型n,而“假”分支缩小到具有可选或缺失属性的类型财产n

const responseGoogleSuccess = (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
  if('googleId' in response) {
      const profile = response.getBasicProfile(); // response is of type GoogleLoginResponse here
  }
}

操场


您当然可以定义自定义类型保护,但在这种情况下使用in运算符要容易得多。但是如果你在几个地方需要这个,可以这样定义类型保护:

type Reposense = GoogleLoginResponse | GoogleLoginResponseOffline;

const responseGoogleSuccess = (response: Reposense) => {
  if (isLoginResponse(response)) {
    const profile = response.getBasicProfile();
  }
}

const isLoginResponse = (response: Reposense): response is GoogleLoginResponse =>
  'googleId' in response;

操场


推荐阅读