如果函数的返回类型为超类,TypeScript能否返回子类? 问题
错误:如果函数的返回类型为超类,TypeScript能否返回子类? 问题,typescript,inheritance,Typescript,Inheritance,错误:类型“Component”上不存在属性“attach”。 如何返回存储在自定义字典类型中的任意子类,并在字典类型具有超类的返回值时使用仅存在于该子类上的方法 上下文 我有一个组件类,它有许多子类。 我的GameActor类可以附加组件。附加的组件存储在自定义类型的ComponentContainer成员中,可以是component的任何子类。例如,MovementComponent、HealthComponent、EventComponent等都可以存储在ComponentContaine
类型“Component”上不存在属性“attach”。
如何返回存储在自定义字典类型中的任意子类,并在字典类型具有超类的返回值时使用仅存在于该子类上的方法
上下文
我有一个组件
类,它有许多子类。
我的GameActor
类可以附加组件。附加的组件存储在自定义类型的ComponentContainer
成员中,可以是component
的任何子类。例如,MovementComponent
、HealthComponent
、EventComponent
等都可以存储在ComponentContainer
中
检索附加组件时,当我尝试从检索到的组件调用方法时,会出现上面的“属性不存在”错误。如果打开浏览器的开发工具,我可以看到返回类型的日志,它看起来实际上是子类类型
组件容器类型定义
GameActor有一系列方法来添加、删除、获取和列出附加组件
//GameActor class that can have Components attached to it
export abstract class GameActor extends GameObject implements IGameActor {
protected components: ComponentContainer;
constructor() {
this.components = {};
}
public getComponent(key: string): Component|null {
return this.components[key];
}
}
// Player subclass of GameActor
export class Player extends GameActor implements IPlayer {
//Player class code here...
}
//Component superclass
export abstract class Component {
protected typeId: string;
public getTypeId(): string {
return this.typeId;
}
}
//EventComponent subclass
export class EventComponent extends Component implements IEventComponent {
public attach(event: Event|CustomEvent): void {
//Attach code here...
}
}
现在,在代码的其他地方,我要执行以下操作:
this.getComponent("EventComponent").attach(PlayerDeathEvent.create(this));
在这一点上,我收到了错误。如果我注销以下代码,则两个代码的类型似乎都是EventComponent
let ec = this.Player.getComponent("EventComponent");
let t = new EventComponent();
我希望
.attach
不会抛出错误,因为编译器知道组件的类型为EventComponent
这里的问题是编译器没有缩小此.getComponent(“EventComponent”)的结果所需的信息
从Component | null
到EventComponent
。方法getComponent()
被声明为获取字符串
并返回组件| null
,因此编译器真正知道的就是这些
let ec = this.Player.getComponent("EventComponent");
let t = new EventComponent();
的确,编译器在一定程度上会根据值的使用方式,将值的类型细化为更具体的类型,即它们的声明方式。。。但这只发生在非常特殊的情况下。编译器无法查看任意代码,并在运行前弄清楚运行时会发生什么。嗯。但是,的确,有很多情况下,编译器并不知道对人类来说显而易见的东西。下面是一个简化的示例:
function hmm(x: number) {
return (x >= 0) ? x : "negative";
}
console.log(hmm(4).toFixed()); // error!
// --------------> ~~~~~~~
// "toFixed" does not exist on number | "negative"
编译器只知道hmm()。对人类来说很明显,hmm(4)
将返回一个数字,因此将有一个toFixed()
方法,并且在运行时确保代码不会出错。但是编译器不知道hmm(4)
最终将计算4>=0
,也不知道4>=0
最终将返回true
,因此它不知道hmm(4)
不会返回“负”
,这意味着它不知道hmm(4)
将有一个toFixed()
方法,这意味着。。。编译器错误
如果您通过更强大的类型显式地向编译器提供信息,您将获得更好的结果,而不是期望编译器从代码流中找出将要发生的事情。我的建议是加强您的ComponentContainer
类型,以表示您在注释中暗示的键值映射,并使getComponent()
成为一个泛型方法,其中key
参数是K
中的泛型keyof ComponentContainer
,它返回类型为ComponentContainer[K]
的值(这是在使用ComponentContainer
对象的K
属性时得到的值)。像这样:
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
}
}