Предположим, я пишу библиотеку, которая позволяет пользователю обрабатывать какие-то объекты. У объекта может быть определено свойство строки type
, и я хотел бы иметь возможность расширять библиотеку с помощью плагинов, которые дополнительно обрабатывают объекты с указанным типом c. Давайте проиллюстрируем это следующим кодом:
type Entry = {
[key: string]: any;
};
type TypedEntry<T extends string> = Entry & {
type: T;
};
type PluginDefinition<T extends string = any> = {
type: T;
process(entry: TypedEntry<T>): void;
};
class Library {
private plugins: Record<string, PluginDefinition> = {};
registerPlugin(plugin: PluginDefinition): void {
this.plugins[plugin.type] = plugin;
}
getPlugin<T extends string>(type: T): PluginDefinition<T> {
return this.plugins[type];
}
}
Пока это работает, но это не оптимально - например, это не ошибка:
this.plugins['foo'] = {
type: 'bar',
process(entry) {},
};
Также единственная причина, по которой getPlugin
метод не выбрасывает ошибки, он видит this.plugins[whatever]
как PluginDefinition<any>
, что удовлетворяет PluginDefinition<T>
.
Обе эти проблемы связаны с тем, что я не могу переписать this.plugins
как сопоставленный тип, потому что на данном этапе нет известного списка типов и, следовательно, нечего отображать. Но в теории ни одна из этих двух проблем не касается, в частности, того, какими будут фактические типы, просто то, что ключ соответствует свойству type
значения.
Есть ли способ переписать Record<string, PluginDefinition>
и Ко. так что эти две проблемы исчезают в пустоте или, возможно, никогда? Я одинаково счастлив с любым из них.