无法为字符串枚举创建用户定义的类型保护

时间:2017-08-30 21:40:46

标签: typescript

我正在创建一个用户定义的类型保护,以确定在运行时获取的(不安全)字符串是否是字符串enum的成员:

enum Vendor {
  ACME = "Acme Co.",
  FOOBAR = "Foo Bar Industries"
}

export let isVendor = (x: string | Vendor): x is Vendor => {
  return !!Vendor[x];
};

当我尝试编译上面的代码时,我会收到以下内容:

[ts] Element implicitly has an 'any' type because expression is not of type 'number'.
(parameter) x: string

一种可能的解决方法如下:

export let isVendor = (x: any): x is Vendor => {
  return !!Vendor[x];
};

...但当我知道该类型至少为any时,我更愿意避免使用string

我可以通过将any的类型签名更改为x来避免使用number | string | Vendor,但这仍然不太理想。

有没有办法在enum上使用字符串执行方括号访问?

1 个答案:

答案 0 :(得分:2)

当我没有隐含任何'打开。我怀疑这可能是编译器问题。

如果您只是将x投射到any

,它就有效
enum Vendor {
   A = "a",
   B = "b"
}

const isVendor = (x: string | Vendor): x is Vendor => {
   return !!Vendor[<any>x];
};

console.info(isVendor("A")); // true
console.info(isVendor("a")); // false
console.info(isVendor("C")); // false

我注意到在此功能的示例中,它们具有类似的强制转换,或者参数的类型为any

另请查看here以获取有关此问题的一些说明。

我仍然认为你需要决定你是否正在寻找名字或价值观。根据您的实施情况,我认为您可能真的在寻找isVendorValue而不是isVendorName。 (我不认为询问名称是Vendor是否有意义,因为它不是;您想知道该值是否为Vendor。):

enum Vendor {
   A = "a",
   B = "b"
}

// doesn't make sense. the name cannot be a Vendor.
const isVendorName = (name: string | Vendor): name is Vendor => {
   return !!Vendor[<any>name];
};

// requires ES7, see below
const isVendorValue = (value: string | Vendor): value is Vendor => {
   return Object.values(Vendor).some((x: any) => x === value);
};

console.info(isVendorName("A"));       // true
console.info(isVendorName("a"));       // false
console.info(isVendorName("C"));       // false
console.info(isVendorName(Vendor.A));  // false

console.info(isVendorValue("A"));      // false
console.info(isVendorValue("a"));      // true
console.info(isVendorValue("C"));      // false
console.info(isVendorValue(Vendor.A)); // true

Object.values显然是ES7,所以这里是另一种实现方式。由于这些值在运行时不会发生变化,因此也可能会从缓存值中受益。

const isVendorValue = (value: string | Vendor): value is Vendor => {
   return Object
      .keys(Vendor)
      .map((key: any) => Vendor[key])
      .some((x: any) => x === value);
};

我现在建议的另一件事我想到的是,与你的建议相反,参数实际上可能实际上是any类型。你说&#34;我知道这个类型至少是string&#34;但这只是不必要地限制了这种方法的用法来测试字符串。

根据您使用该方法的位置,您根本不知道这一点。你知道的是,如果它不是一个字符串,那么它绝对不是Vendor

这个想法是,给定一些对象或值(string与否),确定它是否是此enum的成员,如果是,则将其视为类型系统中的一个。更广泛适用的方法比不必要的方法更好。

const isVendorValue = (value: any): value is Vendor => {
   return typeof value === "string" &&
      Object
      .keys(Vendor)
      .map((key: any) => Vendor[key])
      .some((x: any) => x === value);
};