Прежде всего, обратите внимание, что имена параметров в типах функций обязательны , поэтому это определение необходимо изменить:
interface MyFoo {
foo1: (x: number) => void;
foo2: (x: string) => void;
}
Теперь в Bar<Foo>
нам нужен только один универсальныйпараметр K
в методе boom()
, поскольку для нас будет указан тип Foo
.Я не совсем понимаю ваш вариант использования, поскольку он выглядит как возможно , вы хотите, чтобы boom()
принимал переменное число параметров, но это не соответствует комментарию о том, как вам нужна функция обратного вызова.Поэтому я предполагаю, что boom()
принимает два параметра: имя ключа и функцию обратного вызова:
class Bar<Foo> {
public boom<K extends keyof Foo>(first: K, second: Foo[K]) { }
}
И вот как вы его используете:
// okay, the callback is (x: number) => void
new Bar<MyFoo>().boom("foo1", (x: number) => console.log(x.toFixed(2)));
// error, the callback is (x: number) => void but should be (x: string) => void
new Bar<MyFoo>().boom("foo2", (x: number) => console.log(x.toFixed(2)));
Кстати, этоне мешает вам использовать интерфейс с нефункциональными свойствами:
interface MyFoo { age: number }
new Bar<MyFoo>().boom("age", 40); // okay
Если вам требуется, чтобы boom()
работал только с клавишами, соответствующими функциональным свойствам, вам понадобится какой-нибудь изумительный условные типы :
type KeysMatching<T, V> =
Extract<keyof T, { [K in keyof T]: T[K] extends V ? K : never }[keyof T]>;
class Bar<Foo> {
public boom<K extends KeysMatching<Foo, Function>>(first: K, second: Foo[K]) { }
}
// okay, the callback is (x: number) => void
new Bar<MyFoo>().boom("foo1", (x: number) => console.log(x.toFixed(2)));
// error, the callback is (x: number) => void but should be (x: string) => void
new Bar<MyFoo>().boom("foo2", (x: number) => console.log(x.toFixed(2)));
interface MyFoo { age: number }
// error, "age" is not accepted anymore
new Bar<MyFoo>().boom("age", 40); // error
Надеюсь, что вам это поможет.Удачи!