我有一个名为Parent
的基类:
class Parent {
static elType = window.Element
el: InstanceType<typeof Parent['elType']>
constructor(input: Element) {
let ctor = this.constructor as typeof Parent
if (input instanceof ctor.elType) {
this.el = input
} else {
throw new Error()
}
}
}
仅当input
是构造函数中指定的elType
的实例时,才允许创建实例。如果检查通过,则实例成员el
设置为input
。
然后,我想创建一个仅允许HTMLElement
(扩展了Element
)输入的子类:
class Child extends Parent {
static elType = window.HTMLElement
}
但是,实例成员el
未正确设置为HTMLElement
。仍然是Element
:
let foo = null as unknown as HTMLElement
let ch = new Child(foo)
// Property 'offsetLeft' does not exist on type 'Element'.
ch.el.offsetLeft
我认为问题出在此
el: InstanceType<typeof Parent['elType']>
我正在将el
的类型设置为elType
的{{1}}类型,这是Parent
,不受Element
的静态影响Child
。我的问题是-我该怎么做?我需要一些技巧,例如:
elType
在the playground中进行检查。
我知道我可以通过在el: InstanceType<typeof {{ current class }}['elType']>
中明确声明el
来解决此问题:
Child
但是我想避免这种情况,因为它是多余的。 class Child extends Parent {
static elType = window.HTMLElement
el: HTMLElement
}
应该始终是el
的实例类型。
答案 0 :(得分:1)
如果您不使用静态属性,建议使用polymorphic this
types来表示子类属性将与其他某些属性一起缩小的约束。像这样:
class Parent {
elType = window.Element
el: InstanceType<this['elType']>
constructor(input: Element) {
if (input instanceof this.elType) {
this.el = input as InstanceType<this['elType']>; // assert
} else {
throw new Error()
}
}
}
class Child extends Parent {
elType = window.HTMLElement
}
let foo = null as unknown as HTMLElement
let ch = new Child(foo)
ch.el.offsetLeft; // okay
这里el
的类型声明为InstanceType<this['elType']>
,它将始终与每个子类中elType
的特定类型相关。这就给分配给this.el
了些麻烦,因为编译器无法轻松地验证这种分配对所有子类都是安全的。类型断言是解决该问题的最直接方法。
无论如何,除了elType
属性是实例属性而不是静态属性之外,您几乎都能看到它的行为。
如果您真的想静态地看到它,我可能最终会放弃直接继承,而是使用一个工厂函数为您创建类。像这样:
const ParentMaker = <T extends Element>(elType: new () => T) => {
return class Parent {
static elType = elType;
el: T;
constructor(input: Element) {
let ctor = this.constructor as typeof Parent
if (input instanceof ctor.elType) {
this.el = input
} else {
throw new Error()
}
}
}
}
const Child = ParentMaker(window.HTMLElement);
let foo = null as unknown as HTMLElement
let ch = new Child(foo)
ch.el.offsetLeft
这里ParentMaker
将构造函数作为参数,并返回一个新类,该类的静态和实例端具有elType
和el
属性,这些属性强烈地按照您的方式键入。当然,这里没有简单的继承途径,但这也许就是您所需要的:您可以始终执行class Child extends ParentMaker(window.HTMLElement) { ... }
以使Child
拥有自己的属性和方法。仅在需要子子类或ch instanceof Parent
才能工作时才会遇到麻烦。
希望其中之一可以为您提供一些有关如何进行的想法。祝你好运!