我在抽象类中设置正确类型时遇到问题。我想做如下操作:
abstract class AbstractMap<TTile extends AbstractTile> {
public readonly fields: TTile[];
constructor() {
this.fields = [this.createTile(0,0), this.createTile(0,1)];
}
protected abstract createTile(x: number, y: number): TTile;
}
abstract class AbstractTile {
protected abstract readonly map: AbstractMap<this>;
protected constructor(public readonly x: number, public readonly y: number) {
}
public get neighbors(): this[] {
return this.map.fields.filter(f => f);
}
}
class ServerMap extends AbstractMap<ServerTile> {
protected createTile(x: number, y: number): ServerTile {
return new ServerTile(x, y, this);
}
}
class ServerTile extends AbstractTile {
protected readonly map: ServerMap;
constructor(x: number, y: number, map: ServerMap) {
super(x, y);
this.map = map;
}
}
我尝试在ServerTile.map
属性上获取 ServerMap 类型,但一直都有错误:
Type 'ServerMap' is not assignable to type 'AbstractMap<this>'.
Types of property 'fields' are incompatible.
Type 'ServerTile[]' is not assignable to type 'this[]'.
Type 'ServerTile' is not assignable to type 'this'.
'ServerTile' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'ServerTile'.
我试图在AbstractTile
类中设置AbstractMap<AbstractTile>
而不是AbstractMap<this>
,但随后我需要在AbstractTile.neighbors
函数上设置AbstractTile[]
返回类型。
1条答案
按热度按时间mklgxw1f1#
多态
this
类型是一个隐式F绑定类型。它的作用就像一个被约束到当前类型的generic类型参数。和泛型一样,指定类型参数比编写将其视为未解析参数的代码更容易。在AbstractTile
及其后代类的类体内,我们只知道this
是当前类的某个子类型。但我们不知道是哪一个。这意味着你写的很多代码在技术上可能是不安全的。例如,对于你的代码,有人可能会写:编译器认为
oopses
的类型是Oops[]
,因为这是neighbors
的假定类型。但是ServerMap
的实现并不是这样工作的,所以如果你继续,你会得到一个运行时错误:所以编译器给出的错误消息,
'ServerTile' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'ServerTile'
告诉你问题到底出在哪里。当然,你可能认为这样的事情不太可能发生,所以你想使用
this
类型。这是你的特权,你可以向编译器Assert这不是一个问题:这会抑制编译器错误,现在您有责任确保对于您将遇到的所有
this
类型,ServerMap
的行为都与AbstractMap<this>
相同。如果你真的想用一种更可靠的类型安全的方式来编写这个函数,你可以用隐式的F绑定类型参数
this
来替换 * 显式的F绑定类型参数T
,形式是T extends F<T>
,在你的例子中是class AbstractTile<T extends AbstractTile<T>>
:现在,您可以编写
ServerMap
和ServerTile
,如下所示:所有这些都可以按照需要编译,并且不再可能出现之前的失败模式,因为现在
neighbors
属性的类型是ServerTile[]
,而不是Oops[]
:因此,如果您尝试引用
oopses[0]
的prop
属性,编译器将发出警告。Playground代码链接