【问题标题】:Exhaustively iterate over all values in string union?彻底迭代字符串联合中的所有值?
【发布时间】:2019-09-04 23:11:31
【问题描述】:

我有一个这样的字符串联合:

export type Intervals = 'total' | 'weekly' | 'biweekly' | 'monthly' | 'annually';

我想通过循环遍历联合值的数组来向用户显示这些:

const intervals = ['total', 'weekly', 'biweekly', 'monthly', 'annually'];
intervals.forEach(...);

如何键入intervals 数组以保证它具有Intervals 联合的所有值?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    不是从类型派生数组,而是从数组派生类型。

    export const INTERVALS = ['total', 'weekly', 'biweekly', 'monthly', 'annually'] as const;
    
    const temp = [...INTERVALS];
    export type Interval = typeof temp[0];
    

    【讨论】:

    • 更简单:export type Interval = typeof INTERVALS[number];
    • 这一行中的“数字”是什么意思?
    【解决方案2】:

    确保intervals 必须可分配给Array<Intervals> 很容易:

    const intervalsMisspelled: Array<Intervals> = 
      ['weekly', 'biweekly', 'annually', 'monthly', 'totul']; // error, "totul"
    

    但这并不妨碍你忽略一些事情:

    const intervalsMissing: Array<Intervals> = 
      ['weekly', 'biweekly', 'annually', 'monthly']; // oops, no error but missing "total"
    

    要解决这个问题,您可以创建一个名为 ensureArray() 的辅助函数,该函数接受一个类型参数 T(对您来说将是 Intervals),然后返回一个新函数,该函数接受一个类型为 @ 的参数列表987654329@ 并为该列表推断数组类型A。如果 A 数组 (A[number]) 的元素的类型比 T 窄,那么您一定遗漏了一些内容,您应该得到一个错误。这是一种方法:

    const ensureArray = <T>() => <A extends T[]>(
      ...a: A & ([T] extends [A[number]] ? A : never)
    ): A => a;
    
    const ensureIntervalsArray = ensureArray<Intervals>();
    
    const intervals = ensureIntervalsArray(
      'annually', 'biweekly', 'monthly', 'total', 'weekly'); // okay
    
    const intervalsMisspelled = ensureIntervalsArray(
      'annually', 'biweekly', 'monthly', 'totul', 'weekly'); // error, "totul"
    
    const intervalsMissing = ensureIntervalsArray(
      'annually', 'biweekly', 'monthly', 'weekly'); // error,
    // [string, string, string, string] is not assignable to never
    

    这可行,尽管您在intervalsMissing 上遇到的错误相当神秘,说某些东西不能分配给never,但没有告诉您问题到底是什么。由于 TypeScript 目前不允许我们创建 custom type errors,我们只能尝试解决这个问题。

    下面给出了一个更奇怪的错误信息,但它给了开发者一个提示:

    const ensureArray = <T>() => <A extends T[]>(
      ...a: A & ([T] extends [A[number]] ? A :
        { errorMessage: [Error, "You are missing", Exclude<T, A[number]>] })
    ): A => a;
    
    const ensureIntervalsArray = ensureArray<Intervals>();
    
    const intervalsMissing = ensureIntervalsArray(
      'annually', 'biweekly', 'monthly', 'weekly'); // error,
    // Property 'errorMessage' is missing in type 
    // '["annually", "biweekly", "monthly", "weekly"]' 
    // but required in type '{ errorMessage: [Error, "You are missing", "total"]; }'
    

    希望其中之一足以满足您的需求。祝你好运!

    【讨论】:

      【解决方案3】:

      如何键入区间数组,以保证它具有区间联合的所有值

      不容易。您可以将其声明为 元组 的联合。假设你只有'total' | 'weekly',那么你可以这样做:

      const intervals: 
      | ['total', 'weekly']
      | ['weekly', 'total']
      

      你这里有一个排列nPn

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        • 2010-12-27
        • 1970-01-01
        • 2019-11-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多