【问题标题】:Typescript - Unexpected error when using includes with a typed arrayTypescript - 将包含与类型化数组一起使用时出现意外错误
【发布时间】:2019-09-18 06:23:48
【问题描述】:

使用以下代码,我们生成两个数组:

const PROVIDERS: {
  PROVIDER_1: 'PROVIDER_1';
  PROVIDER_2: 'PROVIDER_2';
  PROVIDER_3: 'PROVIDER_3';
} = {
  PROVIDER_1: 'PROVIDER_1',
  PROVIDER_2: 'PROVIDER_2',
  PROVIDER_3: 'PROVIDER_3',
};

const GOOD_PROVIDERS = [PROVIDERS.PROVIDER_1, PROVIDERS.PROVIDER_2];
const BAD_PROVIDERS = [PROVIDERS.PROVIDER_3];

类型有:

const GOOD_PROVIDERS: ("PROVIDER_1" | "PROVIDER_2")[]
const BAD_PROVIDERS: ("PROVIDER_3"")[]

然后,如果我尝试检查某个值是否包含在其中一个数组中,我会遇到几个我不知道如何处理的编译错误:

const provider: 'PROVIDER_1' | 'PROVIDER_2' | 'PROVIDER_3' = getProvider();
const isGood = GOOD_PROVIDERS.includes(provider);
const isBad = BAD_PROVIDERS.includes(provider);

GOOD_PROVIDERS 的包含抛出此错误

'"PROVIDER_1" 类型的参数 | "PROVIDER_2" | “PROVIDER_3”' 不是 可分配给“PROVIDER_1”类型的参数 | “PROVIDER_2”。类型 '"PROVIDER_3"' 不可分配给类型 '"PROVIDER_1" | "PROVIDER_2"'.ts(2345)

BAD_PROVIDERS 的包含抛出此错误

'"PROVIDER_1" 类型的参数 | "PROVIDER_2" | “PROVIDER_3”' 不可分配给“PROVIDER_3”' 类型的参数。 类型 '"PROVIDER_1"' 不可分配给类型 '"PROVIDER_3"'.ts(2345)

为什么 Array.includes 假定参数已经在列表中?还有其他方法可以检查吗?

【问题讨论】:

标签: typescript


【解决方案1】:

为什么 Array.includes 假定参数已经在列表中?

The link 在您的评论中已经回答了这个问题。 TL;DR 是向数组添加类型类似于创建一组抽象值,并且超出该集合被选择为编译器错误。有些人可能喜欢它,有些人可能讨厌它,但它就是这样(至少现在是这样)。

还有其他方法可以检查吗?

是的。

从 TypeScript 1.6 开始,您可以使用 (x) =&gt; x is <i>Type</i> type guards。我发现这个功能(连同(x) =&gt; asserts x is <i>Type</i> assertion functions)使用起来非常方便,非常有用,老实说有点像魔法:

在以下示例中,我将假设您无法控制 PROVIDERS 对象的定义。如果这样做,请转到下一个示例。

const PROVIDERS: {
  PROVIDER_1: 'PROVIDER_1';
  PROVIDER_2: 'PROVIDER_2';
  PROVIDER_3: 'PROVIDER_3';
} = {
  PROVIDER_1: 'PROVIDER_1',
  PROVIDER_2: 'PROVIDER_2',
  PROVIDER_3: 'PROVIDER_3',
};

type GoodProvider = typeof PROVIDERS.PROVIDER_1 | typeof PROVIDERS.PROVIDER_2;
type BadProvider = typeof PROVIDERS.PROVIDER_3;
type Provider = GoodProvider | BadProvider;

// Notice that types here are broadened, – otherwie this won't work
// The distinction between good vs bad providers has been moved to typings instead
const GOOD_PROVIDERS: Provider[] = [PROVIDERS.PROVIDER_1, PROVIDERS.PROVIDER_2];
const BAD_PROVIDERS: Provider[] = [PROVIDERS.PROVIDER_3];

function isGoodProvider(provider: Provider): provider is GoodProvider {
  return GOOD_PROVIDERS.includes(provider);
}

// You might not need both functions though; but if you do, here's the second one
function isBadProvider(provider: Provider): provider is BadProvider {
  return BAD_PROVIDERS.includes(provider);
}

Try it.

如果您控制了 PROVIDERS 对象,那么您很幸运,因为您可以进行一些主要的优化,包括文本(要编写的代码更少)和逻辑(没有逻辑重复)。

使用as const,您可以定义真值对象,并从中推断出所有必要的类型,这是我一直使用的方法,它的稳健性非常好:

const GOOD_PROVIDERS = {
  PROVIDER_1: 'PROVIDER_1',
  PROVIDER_2: 'PROVIDER_2',
} as const;

const BAD_PROVIDERS = {
  PROVIDER_3: 'PROVIDER_3',
} as const;

type GoodProvider = keyof typeof GOOD_PROVIDERS;
type BadProvider = keyof typeof BAD_PROVIDERS;
type Provider = GoodProvider | BadProvider;

function isGoodProvider(provider: Provider): provider is GoodProvider {
  return provider in GOOD_PROVIDERS;
}

function isBadProvider(provider: Provider): provider is BadProvider {
  return provider in BAD_PROVIDERS;
}

Try it.

【讨论】:

    【解决方案2】:

    我改成some()方法:

    array.some((arr) => arr === otherParameter)
    

    你的情况是:

    const isGood = GOOD_PROVIDERS.some((GOOD_PROVIDER) => GOOD_PROVIDER === provider);
    

    【讨论】:

      猜你喜欢
      • 2016-08-28
      • 2021-01-30
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-29
      • 1970-01-01
      相关资源
      最近更新 更多