我有这样的TypeScript(JavaScript)类:
import * as React from 'react'
export default
class StyleableComponent<PROPS, STATE> extends React.Component<PROPS, STATE> {
protected classes: any
static style: any
someMethod() {
const ctor = this.constructor
console.log(this.constructor.style)
}
}
并且 TypeScript 会抛出此错误:
ERROR in ./src/StyleableComponent.ts
(11,38): error TS2339: Property 'style' does not exist on type 'Function'.
但是,很明显,您可以看到static style: any
是在类定义中声明的。
那么,我们如何正确使用this.constructor
呢?注意,this.constructor
可以是扩展StyleableComponent
类的构造函数,所以this.constructor
可能不是=== StyleableComponent
,但它应该具有style
属性,因为它是从StyleableComponent
扩展的。
例如
interface P {...}
interface S {...}
class Foo extends StyleableComponent<P,S> {...}
console.log(new Foo)
^this.constructor
将被Foo
,StyleableComponent
类需要看Foo.style
。
那么我该怎么做呢?我是否需要以某种方式使用额外的模板类型参数?
静态属性与实例属性继承
如果你想从子类中读取静态属性,你可以用3种方式来完成,有关更多详细信息,您可以看到测试部分。
-
因为
Object.getPrototypeOf(..)
的返回类型是any
,所以可以直接访问 style,例如:someMethod() { let style = Object.getPrototypeOf(this).constructor.style; }
-
因为
this.constructor
的返回类型是Function
,所以首先必须把它赋给一个any
变量,例如:someMethod() { let cotr:any=this.constructor; let style = cotr.style; }
-
因为
Function
是一个接口,所以你可以在 TypeScript 中展开它,例如:declare global{ interface Function{ style:any; } } someMethod() { return this.constructor.style; }
如果你想读取子类style
属性,你必须在构造函数上定义属性,然后子类可以选择通过将style
传递给超类来定义其样式,或者根本不使用。例如:
constructor(protected style:any="default"){
}
有趣的是,除了style
属性之外,子类行为都是一样的。在设计视图中,如果使用静态样式属性,则必须定义另一个子类来实现它,这将倾向于许多具有差异样式的子类。但是当使用实例属性style
时,您可以通过传递带有optional的style
来做到这一点,仅适用于不同的style
。例如:
let bar=new Bar();//use parent's style
let baz=new Bar(null,null,"baz");//use it owned style
您还可以通过在子类的构造函数中传递style
来拒绝其他人传递其样式。例如:
constructor(){
super("style");
}
测试
import * as React from 'react';
declare global {
interface Function {
style: any
}
}
describe('static inheritance', () => {
class StyleableComponent<P, S> extends React.Component<P, S> {
protected classes: any;
static style: any;
constructor(props?: P, context?: any, public style: any = "default") {
super(props, context);
}
someMethod() {
//dangerous if subclass not define static style property
//todo:the 1st approach
// let style = Object.getPrototypeOf(this).constructor.style;
// return style;
//todo:the 2nd approach
// let cotr: any = this.constructor;
// return cotr.style;
//todo:the 3nd approach,you must declare style in Function interface
return this.constructor.style;
}
}
class Foo extends StyleableComponent<any, any> {
static style = "foo";
constructor(props?: any, context?: any) {
super(props, context, Foo.style);
}
}
class Bar extends StyleableComponent<any, any> {
}
test('access style from subclass', function () {
let foo = new Foo();
expect(foo.someMethod()).toBe(Foo.style);
});
test('return undefined if subclass not define style', function () {
let bar = new Bar();
expect(bar.someMethod()).toBeUndefined();
});
test('replace static style with instance property', function () {
let foo = new Foo();
let bar = new Bar();
let baz = new Bar(null, null, "baz");
expect(foo.style).toBe("foo");
expect(bar.style).toBe("default");
expect(baz.style).toBe("baz");
});
});