【问题标题】:Checking if a value is valid for a union type检查一个值是否对联合类型有效
【发布时间】:2018-08-23 11:00:09
【问题描述】:

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

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)。

我们正在考虑使用枚举来表示这种类型,但我想先检查一下我们是否可以使用原生类型来代替。

【问题讨论】:

    标签: typescript typescript2.9


    【解决方案1】:

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

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

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

    【讨论】:

    【解决方案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
    })
    

    【讨论】:

    猜你喜欢
    • 2020-02-24
    • 2021-10-26
    • 2023-01-24
    • 2011-08-10
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 2020-08-04
    相关资源
    最近更新 更多