检查值对于联合类型是否有效

时间:2018-08-23 11:00:10

标签: typescript typescript2.9

假设我在我的应用中定义了这种类型:

type PiiType = 'name' | 'address' | 'email';

我在应用程序周围使用此类型来强制进行一些强类型化。我们可能会从表面上表示PII的服务器上获取信息,并需要根据此类型定义检查PII的类型是否有效。

关于此问题的

A previous solution建议使用第二个数组来复制有效值,并对照该数组的内容检查字符串:

type PiiType = 'name' | 'address' | 'email';

isValidPii(value: string): Boolean {
  const piiTypeValues = ['name', 'address', 'email'];
  return piiTypeValues.indexOf(potentialValue) !== -1;
}

这对我们来说是不可取的,因为它需要两次定义类型,删除单个事实来源,并可能导致错误。

如何在不重复定义的情况下根据此联合类型检查给定值是否有效?

例如,如果有一个像isoftype这样的运算符,我可以这样使用它:

'name' isoftype PiiType;      // true
'hamburger' isoftype PiiType; // false
100 isoftype PiiType;         // false

...但是此运算符不存在,所以我不确定应该怎么做才能检查此类型的值是否有效。 instanceof存在,但仅针对类/接口进行检查,并且typeof仅返回JavaScript类型(例如stringnumber)。

我们正在考虑使用枚举代替此类型,但我想先检查一下是否可以使用本机类型做些什么。

2 个答案:

答案 0 :(得分:3)

诀窍是通过一个标识函数来运行数组,该函数可以推断受string约束的元素类型。这将导致编译器推断文字类型的并集:

function asLiterals<T extends string>(arr: T[]): T[] { return arr; }
const piiTypeValues = asLiterals(['name', 'address', 'email']);
type PiiType = (typeof piiTypeValues)[number];

还有另一种解决方法here,但是上面的方法似乎更简单。

答案 1 :(得分:2)

虽然复制并集不理想,但是我们可以使用编译器来验证并集和重复值是同步的。如果您无法控制工会,这是最安全的方法(否则@ Matt-McCutchen的解决方案是更好的方法)

我们可以利用映射类型和多余的对象文字属性检查来创建一个函数,该函数将采用与联合具有相同键的对象。对象的值无关紧要,我们只使用文字类型0

type PiiType = 'name' | 'address' | 'email';

function isValidBuilder<T extends string>(o: Record<T, 0>) {
  let values = Object.keys(o)
  return function (v: string): v is T {
    return values.indexOf(v) !== -1
  }
}

const isValidPii = isValidBuilder<PiiType>({
  name: 0,
  address: 0,
  email:0
})

// Error  missing key
const isValidPii2 = isValidBuilder<PiiType>({
  name: 0,
  address: 0,

})

//error excess key
const isValidPii4 = isValidBuilder<PiiType>({
  name: 0,
  address: 0,
  email: 0
  other:0
})