在我们的代码库中,我们非常广泛地使用导航器和构建器模式来抽象化组装的分层对象。其核心是Navigator
类,我们使用它遍历不同的类。我目前正在尝试将其迁移到打字稿,但正在努力打字以利用打字稿的力量。
我认为我问题的核心是我不能使用this
作为类的泛型的默认值,例如class Something<T = this>
,或者我无法重载类以某种方式有条件地设置类属性的类型。您能否提供任何有关我如何能够在下面键入Navigator
(和构建器类)的见解?
// I guess what I'd like to do is
// class Navigator<BackT = this> but that's not allowed
class Navigator<BackT> {
// It's this 'back' type I'll like to define more specifically
// i.e. if back is passed to the constructor then it should be 'BackT'
// if back is not passed to the constructor or is undefined, it
// should be 'this'
back: BackT | this;
constructor(back?: BackT) {
this.back = back || this;
}
}
class Builder1<BackT> extends Navigator<BackT> {
builder1DoSomething() {
// Do some work here
return this;
}
}
class Builder2<BackT> extends Navigator<BackT> {
withBuilder1() {
return new Builder1(this);
// Also tried the following, but I got the same error:
// return new Builder1<this>(this);
}
builder2DoSomething() {
// Do some work here
return this;
}
}
// This is fine
new Builder1().builder1DoSomething().builder1DoSomething();
new Builder2()
.withBuilder1()
.builder1DoSomething()
// I get an error here becuase my types are not specific enough to
// let the complier know 'back' has taken me out of 'Builder1' and
// back to 'Builder2'
.back.builder2DoSomething();
答案 0 :(得分:2)
如果没有为类提供类型参数,则可以在back
字段上使用条件类型将其键入为this
。我们将使用void
类型作为默认值,以表示缺少类型参数:
class MyNavigator<BackT = void> {
back: BackT extends void ? this : BackT; // Conditional type
constructor(back?: BackT) {
this.back = (back || this) as any;
}
}
class Builder1<BackT = void> extends MyNavigator<BackT> {
builder1DoSomething() {
return this;
}
}
class Builder2<BackT = void> extends MyNavigator<BackT> {
withBuilder1() {
return new Builder1(this);
}
builder2DoSomething() {
return this;
}
}
new Builder2()
.withBuilder1()
.builder1DoSomething()
// ok now
.back.builder2DoSomething();
答案 1 :(得分:0)
我认为最好的选择是为每个类创建一个特殊的变体,该变体的工作方式与没有构造函数参数的情况类似。因此,有一个特殊的SelfNavigator
,SelfBuilder1
等扩展了它们对应的类,并且本身没有泛型。
class MyNavigator<BackT> {
back: BackT;
constructor(back: BackT) {
this.back = back;
}
}
class SelfMyNavigator extends MyNavigator<SelfMyNavigator> {}
class Builder1<BackT> extends MyNavigator<BackT> {
builder1DoSomething() {
// Do some work here
return this;
}
}
class SelfBuilder1 extends Builder1<SelfBuilder1> {
constructor() {
super((null as unknown) as SelfBuilder1);
this.back = this;
}
}
class Builder2<BackT> extends MyNavigator<BackT> {
withBuilder1() {
return new Builder1(this);
}
builder2DoSomething() {
// Do some work here
return this;
}
}
class SelfBuilder2 extends Builder2<SelfBuilder2> {
constructor() {
super((null as unknown) as SelfBuilder2);
this.back = this;
}
}
// This is fine
new SelfBuilder1().builder1DoSomething().builder1DoSomething();
new SelfBuilder2()
.withBuilder1()
.builder1DoSomething()
.back.builder2DoSomething();
请注意,您无法致电super(this)
,因此使用了丑陋的演员表。有多种方法可以避免这种情况,例如使代码更好。将所有内容都转换为接口和抽象类的系统,以便字段back
不在超类中,而是在超接口中。或者将其设为吸气剂,如果未设置,则返回this
,尽管这仍然需要一些强制转换。