如何对联合类型的两条腿进行运行时检查?

时间:2017-09-28 12:14:11

标签: typescript

我有一个具有以下类型的变量:

const data: { error: string; } | { property1: string; };

(这是外部API的响应,因此我无法更改它。)

我现在想检查data这两种可能类型中的哪一种。我试过这个:

if (typeof data.error !== 'undefined') { }

不幸的是,TypeScript然后抱怨

Property `error` does not exist on type `{ property1: string }`.

如何让TypeScript知道它是哪种类型?

3 个答案:

答案 0 :(得分:2)

这正是TypeScript拥有user-defined type guards的原因。您可以告诉TypeScript如何区分联合的两个成员:

function dataHasError(data: { error: string; } | { property1: string; }): data is { error: string; } {
  return 'error' in data;
}

然后它会在if / else子句中以预期的方式缩小类型:

const data: { error: string; } | { property1: string; } = /* API response */;

if (dataHasError(data)) {
  console.log(data.error); // okay
} else {
  console.log(data.property1); // okay
}

如果您经常发现自己需要通过检查是否存在密钥来缩小范围,可以在库中放置以下类型保护:

function hasKey<K extends string>(obj: any, key: K): obj is Record<K, any> {
  return key in obj;
}

然后可以这样写:

if (hasKey(data, 'error')) {
  console.log(data.error); // okay
} else {
  console.log(data.property1); // okay
}

相关说明:TypeScript有一个suggestion可以自动将key in obj解释为类型保护,以便以下内容可以正常使用:

if ('error' in data)) {
  console.log(data.error); // would be okay, currently error
} else {
  console.log(data.property1); // would be okay, currently error
}

目前(从TypeScript v2.5开始)不属于该语言,因此用户定义的类型保护是目前最好的答案。

希望有所帮助;祝你好运!

答案 1 :(得分:0)

我能想到的一种简单方法是使用一种具有optional属性而不是联合类型的类型。像这样:

async void OnLoginButtonClicked(object sender)
{
    try
    {
        ....//previous code
        await Task.Run( () =>
          {
            _navigationservice.NavigateTo(Locator.MainPageViewModel);
          });
    }
    catch (MsalException ex)
    {

        //
    }
}

答案 2 :(得分:0)

这是我目前正在使用的解决方法。作为一种解决方法,它很好,但我宁愿正确使用TypeScript的类型系统:

const data: any = /* API response */;

if (data.error) {
  const errorData: { error: string; } = data;
  // Do whatever
}

const actualData: { property1: string; } = data;