Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果函数的返回类型为超类,TypeScript能否返回子类? 问题_Typescript_Inheritance - Fatal编程技术网

如果函数的返回类型为超类,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

    }
}