проблема
Предположим, у меня есть такой код:
// Events we might receive:
enum EventType { PlaySong, SeekTo, StopSong };
// Callbacks we would handle them with:
type PlaySongCallback = (name: string) => void;
type SeekToCallback = (seconds: number) => void;
type StopSongCallback = () => void;
В API, который мне дан, я могу зарегистрировать такой обратный вызов с помощью
declare function registerCallback(t: EventType, f: (...args: any[]) => void);
Но я хочу избавиться от этого any[]
и убедиться, что не могу зарегистрировать некорректно введенную функцию обратного вызова.
Решение?
Я понял, что могу сделать это:
type CallbackFor<T extends EventType> =
T extends EventType.PlaySong
? PlaySongCallback
: T extends EventType.SeekTo
? SeekToCallback
: T extends EventType.StopSong
? StopSongCallback
: never;
declare function registerCallback<T extends EventType>(t: T, f: CallbackFor<T>);
// Rendering this valid:
registerCallback(EventType.PlaySong, (name: string) => { /* ... */ })
// But these invalid:
// registerCallback(EventType.PlaySong, (x: boolean) => { /* ... */ })
// registerCallback(EventType.SeekTo, (name: string) => { /* ... */ })
Это действительно изящно и мощно! Такое ощущение, что я использую зависимые типы: я в основном написал себе функцию, отображающую значения в типы, здесь.
Однако я не знаю всей силы системы типов TypeScript и, возможно, есть еще лучший способ сопоставления значений перечисления с такими типами.
Вопрос
Есть ли лучший способ сопоставить значения перечисления с такими типами? Можно ли избежать действительно большого условного типа, как указано выше? (На самом деле у меня много событий, и это своего рода беспорядок: VS Code показывает огромное выражение, когда я наводю курсор на CallbackFor
, и мой линтер действительно хочет делать отступ после каждого :
.)
Я бы хотел записать значения перечисления объектного сопоставления в типы, чтобы я мог объявить registerCallback
, используя T
и CallbackFor[T]
, но это не похоже на вещь. Любые идеи приветствуются!