#typescript #generics #this
#typescript #общие #это
Вопрос:
Когда я использую следующий код, я получаю ошибку, описанную в комментарии. Чего мне здесь не хватает?
type MyEvent<S extends Bindable> = {
source: S;
};
type MyListener<S extends Bindable> =
(event: MyEvent<S>) => void;
interface Bindable {
listener: MyListener<this>;
};
interface Row extends Bindable {
id: number;
}
declare var e: MyEvent<Row>;
// ^
// Type 'Row' does not satisfy the constraint 'Bindable'.
// Types of property 'listener' are incompatible.
// Type 'MyListener<Row>' is not assignable to type 'MyListener<Bindable>'.
// Property 'id' is missing in type 'Bindable' but required in type 'Row'.ts(2344)
Комментарии:
1. Какую версию Typescript вы используете?
2. Я использую typescript 4.0.2
Ответ №1:
this
ссылается на Bindable, тогда как вы хотите, чтобы он ссылался на Row
. Сделайте это вместо:
type MyEvent<S extends Bindable<S>> = {
source: S;
}
type MyListener<S extends Bindable<S>> = (event: MyEvent<S>) => void;
interface Bindable<Self extends Bindable<Self>> {
listener: MyListener<Self>;
}
interface Row extends Bindable<Row> {
id: number;
}
declare var e: MyEvent<Row>;
Редактировать: или одно небольшое изменение может быть лучше для вашего варианта использования:
interface Bindable {
listener: MyListener<Bindable>;
}
Комментарии:
1. Это именно то, чего я пытаюсь избежать, используя ‘this’. Но проблема заключается в сигнатуре функции MyListener. Если я изменю тип свойства прослушивателя на MyEvent<this> (что, конечно, не то, что я пытаюсь сделать), он не жалуется
Ответ №2:
Теперь я понимаю свою проблему. Дело в том, что следующий код нарушил бы ограничение.
interface Unrelated extends Bindable {
prop: number;
}
var bindable: Bindable;
declare var row: Row;
declare var listener: MyListener<Unrelated>;
bindable = row;
bindable.listener = listener;
поскольку MyListener<Unrelated>
значение
будет присвоено MyListener<Row>
свойству.
Фактически, после дальнейшего тестирования я обнаружил, что следующий код:
interface A {
prop: (parm: this) => void;
}
interface B extends A {
propB: number;
}
interface C extends A {
propC: number;
}
declare var b: B;
declare var c: C;
var a: A;
a = b;
имеет ту же проблему, но если я изменю interface A
на:
interface A {
prop: this
}
это не так, что должно выдавать ту же ошибку, потому что я мог бы присвоить значение C реквизиту B, который имеет тип B через переменную a.