Проблема здесь в том, что у компилятора нет информации, необходимой для сужения результатов this.getComponent("EventComponent")
с Component | null
до EventComponent
. Объявлен метод getComponent()
, который принимает string
и возвращает Component | null
, так что это все, что действительно знает компилятор.
Это правда, что компилятор выполняет определенное количество анализа потока управления , где он уточняет типы значений до более конкретных типов, чем они объявлены, в зависимости от того, как они используются. ... но это происходит только в очень специфических обстоятельствах, и ни в коем случае не идеален . Компилятор не может посмотреть на произвольный код и выяснить, что именно произойдет во время выполнения, прежде чем он запустится. Ну, технически никто не может этого сделать . Но да, есть много случаев, когда то, что очевидно для человека, не известно компилятору. Вот упрощенный пример:
function hmm(x: number) {
return (x >= 0) ? x : "negative";
}
console.log(hmm(4).toFixed()); // error!
// --------------> ~~~~~~~
// "toFixed" does not exist on number | "negative"
Компилятор знает только, что hmm()
принимает number
и возвращает number | "negative"
. Для человека очевидно, что hmm(4)
вернет число и, следовательно, будет иметь метод toFixed()
, и, конечно же, во время выполнения код выполняется без ошибок. Но компилятор не знает, что hmm(4)
будет в итоге вычислять 4 >= 0
, и он не знает, что 4 >= 0
в конечном итоге вернет true
, и поэтому он не знает, что hmm(4)
не будетвернуть "negative"
, что означает, что он не знает, что hmm(4)
будет иметь метод toFixed()
, что означает ... ошибка компилятора.
Вместо того, чтобы ожидать, что компилятор выяснит, что произойдет из потока кода, у вас будут лучшие результаты, если вы дадите компилятору информацию явно через более сильные типы. Я рекомендую усилить ваш тип ComponentContainer
, чтобы он отображал отображение значения ключа, которое вы подразумевали в ваших комментариях, и сделать getComponent()
универсальным методом, в котором параметр key
имеет универсальный тип K
из числа keyof ComponentContainer
,и он возвращает значение типа ComponentContainer[K]
(это то, что вы получаете, когда просматриваете свойство K
объекта ComponentContainer
). Например:
type ComponentContainer = {
EventComponent: EventComponent;
// MovementComponent: MovementComponent,
// FooComponent: FooComponent
// etc
}
abstract class GameActor {
protected components: ComponentContainer;
constructor() {
// better actually initialize this properly
this.components = {
EventComponent: new EventComponent()
// MovementComponent: new MovementComponent();
// FooComponent: new FooComponent();
// etc
}
}
public getComponent<K extends keyof ComponentContainer>(key: K): ComponentContainer[K] {
return this.components[key];
}
}
Теперь, когда вы вызываете свой метод, он должен работать так, как вы ожидаете:
// Player subclass of GameActor
class Player extends GameActor {
bloop() {
this.getComponent("EventComponent").attach(PlayerDeathEvent.create(this)); // okay
}
}
Хорошо, надеюсь, это поможет;удачи!
Ссылка на код