#typescript
#typescript
Вопрос:
У меня есть объединение строк, подобное этому:
export type Intervals = 'total' | 'weekly' | 'biweekly' | 'monthly' | 'annually';
Я хочу отобразить их пользователю, перебрав массив значений объединения:
const intervals = ['total', 'weekly', 'biweekly', 'monthly', 'annually'];
intervals.forEach(...);
Как я могу ввести intervals
массив таким образом, чтобы он гарантированно содержал все значения Intervals
объединения?
Ответ №1:
Вместо того, чтобы выводить массив из типа, выводите тип из массива.
export const INTERVALS = ['total', 'weekly', 'biweekly', 'monthly', 'annually'] as const;
const temp = [...INTERVALS];
export type Interval = typeof temp[0];
Комментарии:
1. еще проще:
export type Interval = typeof INTERVALS[number];
2. что означает «число» в этой строке?
3. Я этого не понимаю.
temp
это просто мелкая копия исходного массива иtemp[0]
является первым элементом этого массива, который является'total'
иtypeof temp[0]
должен быть справедливымstring
. Чего мне здесь не хватает?
Ответ №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
для вас), а затем возвращает новую функцию, которая принимает список параметров типа T
и выводит тип массива A
для этого списка. Если элементы A
array ( A[number]
) имеют более узкий тип, чем T
, то вы, должно быть, что-то пропустили, и вы должны получить сообщение об ошибке. Вот способ сделать это:
const ensureArray = <T>() => <A extends T[]>(
...a: A amp; ([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 в настоящее время не позволяет нам создавать ошибки пользовательского типа, мы можем только попытаться обойти это.
Следующее дает еще более странное сообщение об ошибке, но оно дает разработчику подсказку:
const ensureArray = <T>() => <A extends T[]>(
...a: A amp; ([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
.