遍历字符串联合中的所有值?

时间:2019-04-15 00:25:45

标签: typescript

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

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

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

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

如何键入intervals数组,以确保它具有Intervals并集的所有值?

3 个答案:

答案 0 :(得分:3)

很容易确保必须将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),然后返回一个新函数,该函数需要一个类型为T的参数列表,并为该列表推断数组类型为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"]; }'

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

答案 1 :(得分:1)

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

export const INTERVALS = ['total', 'weekly', 'biweekly', 'monthly', 'annually'] as const;

const temp = [...INTERVALS];
export type Interval = typeof temp[0];

答案 2 :(得分:0)

  

如何键入interval数组,以确保它具有Intervals联合的所有值

不容易。您可以将其声明为 tuples 的并集。假设您只有'total' | 'weekly',则可以这样做:

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

这里有一个排列nPn