#typescript
#typescript
Вопрос:
Я полагаю, об этом уже спрашивали раньше, но у меня возникли проблемы с формулировкой, чтобы найти решения, поэтому заранее приношу извинения.
У меня есть тип перечисления:
enum Events {
FOO = 'foo',
BAR = 'bar'
}
У меня есть функция, которая, в свою очередь, принимает функцию. Функция, которую она принимает, имеет тип EventHandler
export const wrapEventFn = async (fn: EventHandler): Promise<unknown> => {
...
Определение типа для EventHandler
:
type EventHandler = (event: Events) => Promise<void>
Теперь функции, которые я передаю, сами ограничены в том, какие события они могут обрабатывать. Например:
export const actionHandler = async (
event: Events.FOO
): Promise<void> => {...
Выполнение вышеуказанного не работает, и TS выдает ошибку:
wrapEventFn(actionHandler) // actionHandler is underlined w error
Ошибка
Argument of type '(event: Events.FOO) => Promise<void>' is not assignable to parameter of type 'EventHandler'.
Types of parameters 'event' and 'event' are incompatible.
Type 'Events' is not assignable to type
Как я могу это исправить?
Комментарии:
1.
(event: Events.FOO): Promise<void>
не удается обработать ни одно изEvents
них, кроме определенного — отсюда ошибка2. Не могли бы вы добавить еще немного информации о том, что
wrapEventFn
делает?3. Пожалуйста, взгляните на эту проблему: github.com/microsoft/TypeScript/issues/21998
4. Ошибка полностью верна. Ваш
actionHandler
обрабатывает только один из возможныхEvents
, но определениеEventHandler
предполагает, что его можно вызвать с любымEvent
Ответ №1:
Вместо enum
этого используйте строковые литеральные типы
type Events = 'foo' | 'bar'
Теперь заставьте EventHandler использовать универсальный объект, который можно присвоить типу Events
:
type EventHandler<T extends Events> = (event: T) => Promise<void>;
declare function wrapEventFn<T extends Events>(fn: EventHandler<T>): Promise<unknown>;
Теперь мы можем создать ваш тип, который является известным подмножеством доступных событий:
type SpecializedEvents = 'foo';
declare function actionHandler(event: SpecializedEvents): Promise<void>;
Теперь мы можем назвать это так:
wrapEventFn<SpecializedEvents>(actionHandler);
Как оказалось, нам даже не нужно указывать общий тип, компилятор typescript может вывести его. Гораздо удобнее просто написать это:
wrapEventFn(actionHandler);
Чтобы продемонстрировать, что это работает, мы можем попытаться передать несовместимый тип в:
type CompletelyTheWrongType = 'this' | 'is' | 'wrong';
declare function wrongActionHandler(event: CompletelyTheWrongType): Promise<void>;
wrapEventFn(wrongActionHandler);
Ошибка, которую это выдает, выглядит следующим образом:
Аргументы типа ‘(event: CompletelyTheWrongType) => Обещание’ не могут быть присвоены параметру типа ‘EventHandler’…