我有一个这样的字符串联合体:
export type Intervals = 'total' | 'weekly' | 'biweekly' | 'monthly' | 'annually';
我想通过遍历联合值数组来向用户显示这些信息:
const intervals = ['total', 'weekly', 'biweekly', 'monthly', 'annually'];
intervals.forEach(...);
如何键入intervals
数组,以确保它具有Intervals
并集的所有值?
答案 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
。