У меня есть объекты, содержащие функции:
const messages = {
helloYou: (name: string) => `Hello ${name}`,
goodbye: () => 'Good bye',
}
и класс, управляющий этим типом объекта:
class MyClass<T> {
…
getMessage<K extends keyof T>(name: K): T[K] {
…
}
…
}
Затем я могу ввести безопасный вызов функции объекта, зарегистрированного в классе:
myObject = new MyClass<typeof messages>(messages)
myObject.getMessage('helloYou')('John')
myObject.getMessage('goodbye')()
Проблема в том, что getMessage
возвращает функцию, и в случае, если мне не нужны параметры (как в примере goodbye
выше), я, скорее всего, забуду пустую скобку. Поэтому я попытался написать функцию, принимая как имя сообщения, так и параметры. Вот что мне удалось сделать:
export function t<O extends Messages & { [P in K]: (arg1: P1) => string }, K extends keyof O, P1>(myObject: MyClass<O> name: K, p1: P1): string
(эта функция, разумеется, перегружена для 0, 2, 3, 4… параметров функции)
Эта функция используется следующим образом:
t(myObject, 'helloYou', 'John')
Это работает хорошо и безопасно для типов, но я бы предпочел, чтобы этот метод t
был методом MyClass
вместо того, чтобы задавать myObject
в качестве первого параметра каждого вызова. Действительно, было бы элегантнее назвать это так:
myObject.t('helloYou', 'John')
Но, как вы можете видеть в методе t
, мне удалось наложить ограничения на тип объекта O
(которые соответствуют типу объекта T
, зарегистрированному в MyClass
) в зависимости от других параметров функции. Если я хочу, чтобы t
был методом класса, мне нужно инвертировать ограничения, т.е. ограничить другие параметры для O
.
Кто-нибудь знает, как это сделать?
Спасибо.
почему бы вам просто не вызвать функции для объекта сообщений, например
myObject.messages.goodbye();
? Почему вы передаете общийnew MyClass<typeof messages>(messages)
, если его можно просто опустить, напримерnew MyClass(messages);
? Какую проблему вы пытаетесь решить? Это действительно похоже на какую-то сверхинженерию.Я напечатал только достаточно кода, чтобы вы могли понять проблему, поэтому вы не видите причин, по которым я хочу это сделать. Просто чтобы уточнить, на самом деле конструктор
MyClass
принимает в качестве параметров не сообщения, а карту сообщений. Если я добавлю, что настоящее имя ̀MyClass` —I18n
, вы, вероятно, лучше поймете, что я пытаюсь сделать… ;)