[英]Determine class instance member type based on static member type in subclass
I have a base class called Parent
:我有一个名为
Parent
的基础 class :
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()
}
}
}
It allows instances to be created only if input
is an instance of elType
specified in the constructor.只有当
input
是构造函数中指定的elType
实例时,它才允许创建实例。 If the check passes, an instance member el
is set to input
.如果检查通过,则将实例成员
el
设置为input
。
Then, I want to create a subclass that allows only HTMLElement
(which extends Element
) inputs:然后,我想创建一个只允许
HTMLElement
(扩展Element
)输入的子类:
class Child extends Parent {
static elType = window.HTMLElement
}
However, the instance member el
is not correctly set to HTMLElement
.但是,实例成员
el
未正确设置为HTMLElement
。 It's still Element
:它仍然是
Element
:
let foo = null as unknown as HTMLElement
let ch = new Child(foo)
// Property 'offsetLeft' does not exist on type 'Element'.
ch.el.offsetLeft
I think the problem lies in this:我认为问题在于:
el: InstanceType<typeof Parent['elType']>
I'm setting the type of el
to the elType
type of Parent
, which is Element
and is not affected by Child
's static elType
.我将
el
的类型设置为Parent
的elType
类型,它是Element
并且不受Child
的 static elType
的影响。 My question is - how can I make that work?我的问题是 - 我怎样才能使它工作? I need some trick like:
我需要一些技巧,例如:
el: InstanceType<typeof {{ current class }}['elType']>
Check this in the playground .在操场上检查这个。
I know I can solve it by explicitly declaring el
in Child
:我知道我可以通过在
Child
中明确声明el
来解决它:
class Child extends Parent {
static elType = window.HTMLElement
el: HTMLElement
}
But I want to avoid that as it's redundant.但我想避免这种情况,因为它是多余的。
el
should always be the instance type of static elType
. el
应该始终是static elType
的实例类型。
If you weren't using static properties, I'd suggest using polymorphic this
types to represent the constraint that a subclass property will narrow in concert with some other property.如果您没有使用 static 属性,我建议使用多态
this
类型来表示子类属性将与其他一些属性一起缩小的约束。 Something like this:像这样的东西:
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
Here the type of el
is declared as InstanceType<this['elType']>
, which will always be related to the specific type of elType
in each subclass.这里
el
的类型被声明为InstanceType<this['elType']>
,它总是与每个子类中elType
的具体类型相关。 That makes assigning something to this.el
a little tricky, since the compiler can't easily verify that such an assignment is safe for all subclasses.这使得给
this.el
赋值有点棘手,因为编译器不能轻易地验证这样的赋值对于所有子类都是安全的。 A type assertion is the most straightforward way around that.类型断言是最直接的方法。
Anyway you can see that this behaves almost exactly as you want, except that the elType
property is an instance property and not static.无论如何,您可以看到它的行为几乎完全符合您的要求,除了
elType
属性是实例属性而不是 static。
If you really want to see this statically, I'd probably end up moving away from straight inheritance and instead I'd use a factory function that creates classes for you.如果你真的想静态地看到这个,我可能最终会离开直接的 inheritance 而是使用工厂 function 为你创建类。 Like this:
像这样:
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
Here ParentMaker
takes a constructor as an argument and returns a new class whose static and instance side have elType
and el
properties strongly typed the way you want.这里
ParentMaker
将构造函数作为参数并返回一个新的 class ,其 static 和实例端具有elType
和el
属性以您想要的方式强类型化。 Of course there's no easy route to inheritance here, but maybe that's all you need: you could always do class Child extends ParentMaker(window.HTMLElement) {... }
to make Child
have its own properties and methods.当然,这里没有通往 inheritance 的简单路线,但也许这就是你所需要的:你总是可以做
class Child extends ParentMaker(window.HTMLElement) {... }
以使Child
拥有自己的属性和方法。 You'd only run into trouble if you needed sub-subclasses or for ch instanceof Parent
to work.如果您需要子类或
ch instanceof Parent
工作,您只会遇到麻烦。
Hopefully one of those gives you some ideas for how to proceed.希望其中一个能给你一些关于如何进行的想法。 Good luck!
祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.