TypeScript:定义了解子 class 属性的父 class 的构造函数
TypeScript: Defining constructor of parent class which is aware of child class's properties
abstract class Parent {
public foo: string;
constructor(v: Partial<Parent>) {
Object.assign(this, v);
}
}
class ChildA extends Parent {
bar: string;
}
class ChildB extends Parent {
baz: string
}
在此设置中,
const a = new ChildA({ foo: 'foo', bar: 'bar'});
出现以下错误。
TS2345: Argument of type '{ foo: string; bar: string }' is not assignable to parameter of type 'Partial<Parent>'.
Object literal may only specify known properties, and 'bar' does not exist in type 'Partial<Parent>'.
constructor<T extends Parent>(v: Partial<T>)
也不起作用。 (TS1092:类型参数不能出现在构造函数声明中。)
我能否以类型安全的方式定义 类 Parent、ChildA 和 ChildB 的构造函数?
我认为打字稿错误是正确的
Parent
只存在foo: string
变量
如果你想 new ChildA
你需要在 ChildA
中定义构造来纠正从外部传递的类型
abstract class Parent {
public foo: string;
protected constructor(v: Partial<Parent>) {
Object.assign(this, v);
}
}
class ChildA extends Parent {
bar: string;
constructor(v: Partial<ChildA>) {
super(v);
}
}
const a = new ChildA({ foo: 'foo', bar: 'bar'});
您想在构造函数参数中使用 the polymorphic this
type。
不幸的是,这是明确不支持的;参见 microsoft/TypeScript#5449, especially this comment, and a related feature request at microsoft/TypeScript#5863. There's a relatively recent feature request to allow this
in constructor parameters at microsoft/TypeScript#40451。那么现在,没有简单的方法告诉编译器您希望构造函数参数取决于“当前”class 构造函数的类型(因此被 subclasses 继承)。
如果你想要这种行为,你不会从 TypeScript 中免费获得它;你必须解决它。
多态-this
是一种“隐式”F-bounded polymorphism, meaning that you can think of this
being like a generic type parameter which is constrained 自身。由于我们无法获得构造函数参数的隐式版本,也许我们可以通过向 class:
添加一个自界类型参数来 显式 来做到这一点
abstract class Parent<T extends Parent<T>> {
public foo: string = "";
constructor(v: Partial<T>) {
Object.assign(this, v);
}
}
行得通;请注意在 Parent<T>
中,类型参数 T
是如何被限制为 Parent<T>
本身的。现在我们可以使用 T
代替 this
类型。当我们声明 subclasses 时,我们需要明确指出:
class ChildA extends Parent<ChildA> {
bar: string = "";
}
class ChildB extends Parent<ChildB> {
baz: string = ""
}
现在您的子classes 的行为符合预期:
new ChildA({ foo: 'foo', bar: 'bar' }).bar;
您提到您可能想给 T
一个 default,这样您就可以在代码的其他部分仅提及 Parent
。对于此默认值,您有多种选择,具体取决于您想要的迂腐与方便程度。最方便的是any
,次之最迂腐的是Parent<any>
,然后是Parent<Parent<any>>
(按需要重复),最后是极端版本:
type ParentItself = Parent<ParentItself>;
abstract class Parent<T extends Parent<T> = ParentItself> { /* ... */ }
也许您甚至希望将 never
作为默认值,这可能会突出显示 Parent
在只有具体子 class 才有意义的地方的任何意外使用。您需要根据您的用例检查这些,看看哪些(如果有)是合适的。
abstract class Parent {
public foo: string;
constructor(v: Partial<Parent>) {
Object.assign(this, v);
}
}
class ChildA extends Parent {
bar: string;
}
class ChildB extends Parent {
baz: string
}
在此设置中,
const a = new ChildA({ foo: 'foo', bar: 'bar'});
出现以下错误。
TS2345: Argument of type '{ foo: string; bar: string }' is not assignable to parameter of type 'Partial<Parent>'.
Object literal may only specify known properties, and 'bar' does not exist in type 'Partial<Parent>'.
constructor<T extends Parent>(v: Partial<T>)
也不起作用。 (TS1092:类型参数不能出现在构造函数声明中。)
我能否以类型安全的方式定义 类 Parent、ChildA 和 ChildB 的构造函数?
我认为打字稿错误是正确的
Parent
只存在foo: string
变量
如果你想 new ChildA
你需要在 ChildA
中定义构造来纠正从外部传递的类型
abstract class Parent {
public foo: string;
protected constructor(v: Partial<Parent>) {
Object.assign(this, v);
}
}
class ChildA extends Parent {
bar: string;
constructor(v: Partial<ChildA>) {
super(v);
}
}
const a = new ChildA({ foo: 'foo', bar: 'bar'});
您想在构造函数参数中使用 the polymorphic this
type。
不幸的是,这是明确不支持的;参见 microsoft/TypeScript#5449, especially this comment, and a related feature request at microsoft/TypeScript#5863. There's a relatively recent feature request to allow this
in constructor parameters at microsoft/TypeScript#40451。那么现在,没有简单的方法告诉编译器您希望构造函数参数取决于“当前”class 构造函数的类型(因此被 subclasses 继承)。
如果你想要这种行为,你不会从 TypeScript 中免费获得它;你必须解决它。
多态-this
是一种“隐式”F-bounded polymorphism, meaning that you can think of this
being like a generic type parameter which is constrained 自身。由于我们无法获得构造函数参数的隐式版本,也许我们可以通过向 class:
abstract class Parent<T extends Parent<T>> {
public foo: string = "";
constructor(v: Partial<T>) {
Object.assign(this, v);
}
}
行得通;请注意在 Parent<T>
中,类型参数 T
是如何被限制为 Parent<T>
本身的。现在我们可以使用 T
代替 this
类型。当我们声明 subclasses 时,我们需要明确指出:
class ChildA extends Parent<ChildA> {
bar: string = "";
}
class ChildB extends Parent<ChildB> {
baz: string = ""
}
现在您的子classes 的行为符合预期:
new ChildA({ foo: 'foo', bar: 'bar' }).bar;
您提到您可能想给 T
一个 default,这样您就可以在代码的其他部分仅提及 Parent
。对于此默认值,您有多种选择,具体取决于您想要的迂腐与方便程度。最方便的是any
,次之最迂腐的是Parent<any>
,然后是Parent<Parent<any>>
(按需要重复),最后是极端版本:
type ParentItself = Parent<ParentItself>;
abstract class Parent<T extends Parent<T> = ParentItself> { /* ... */ }
也许您甚至希望将 never
作为默认值,这可能会突出显示 Parent
在只有具体子 class 才有意义的地方的任何意外使用。您需要根据您的用例检查这些,看看哪些(如果有)是合适的。