Тип параметра TypeScript представляет собой объединение нескольких типов: как определить, что было предоставлено, и работать с ним? - PullRequest
0 голосов
/ 18 апреля 2020

Я работаю с библиотекой React Google Login в TypeScript. У него есть привязки типов для 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 в параметре response, например,

«Property» getBasicProfile 'не существует для типа GoogleLoginResponseOffline' '

Я пробовал следующее для приведения или проверки типа параметра, но все выдают ошибки того или иного типа. Моя функция выглядит следующим образом:

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 с похожими заголовками, но ни один из них не охватывает это.

Ответы [ 3 ]

2 голосов
/ 18 апреля 2020

Вы можете использовать оператор 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;

Playground

1 голос
/ 18 апреля 2020

Что вам нужно, это определяемый пользователем тип защиты: https://www.typescriptlang.org/docs/handbook/advanced-types.html#user -defined-type-guards .

В вашем случае вы будете проверять тип на основе содержимого объекта поступая во время выполнения и не основываясь на его структуре, которая является ранее упомянутым интерфейсом

function isGoogleLoginResponse(response: GoogleLoginResponse|GoogleLoginResponseOffline): response is GoogleLoginResponse {
    // you can check more properties here off course
    return (response as GoogleLoginResponse).googleId !== undefined; 
}

Имея это на месте, вы можете использовать функцию в состоянии if, тогда внутри if вы можете используйте объект ответа, так как GoogleLoginResponse машинопись будет понимать это.

0 голосов
/ 18 апреля 2020

Вы пытались использовать утверждение типа, например,

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

  if((response as GoogleLoginResponse).googleId){   
    // do something with (response as GoogleLoginResponse).googleId
  }
}

Машинопись

...