如何在基类代码中引用"this.constructor"上的静态属性?



我有这样的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将被FooStyleableComponent类需要看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");
});
});

相关内容

最新更新