当非抽象类工作正常时,为什么不能使用TypeScript抽象类的类型来创建React工厂?

时间:2016-09-20 16:22:27

标签: reactjs typescript abstract-class

以下使用React的Typescript代码编译并且工作得很好:

import * as React from "react";

class MyComponent<P> extends React.Component<P, any> {
    static getFactory() {
        return React.createFactory(this);
    }
}

但是,下面的代码(除了类之外的各种方式现在都是抽象的)在编译时会在创建工厂的行上引发错误:

import * as React from "react";

abstract class MyComponent<P> extends React.Component<P, any> {
    static getFactory() {
        return React.createFactory(this);
    }
}

错误是:

  

错误TS2345:构建:类型&#39;类型MyComponent&#39;的参数不能分配给&#39; ComponentClass&lt; any&gt;类型的参数| StatelessComponent&LT;任何&GT;&#39;

我认为没有理由为什么这个类被标记为抽象是否应该有所不同。

有关为何可能出现这种情况的任何见解?

================ ADDED 9/22/2016 =============

在上面的示例中,我可能应该调用MyComponent之类的MyBaseComponent。这里的重点是我正在创建一个我永远不想实例化的框架组件。我只希望实例化从MyComponent派生的东西。 (例如,请注意,MyComponent甚至没有声明render()方法。)

所以....我宣布一个真正被实例化的类:

interface MyDerivedComponentProps {
    id: string;
}

class MyDerivedComponent extends MyComponent<MyDerivedComponentProps> {
    render() {
        return /* Some JSX rendering stuff here */
    }
}

请注意,这一切都运行正常....如果我没有实例化MyComponent但是实例化MyDerivedComponent。但是使用abstract关键字来装饰MyComponent的简单行为(应该用于确保MyComponent永远不会直接实例化)会导致此编译器错误。我仍然认为不应该这样做。如果基类未标记为抽象,则编译器正在处理继承。如果基类被标记为抽象,或者可能没有,那么它也应该处理得很好,但如果没有,为什么呢?

================ ADDED 9/29/2016 =============

根据评论中的请求,这里有一个完整的示例代码,显示了两者的声明和继承:

import * as React from "react";
import * as ReactDOM from "react-dom";

interface MyDerivedComponentProps {
    id: string;
}

// WORKING EXAMPLE
class MyBaseNonAbstractComponent<P> extends React.Component<P, any> {
    static getFactory() {
        return React.createFactory(this);  // NO COMPILER ERROR HERE
    }
}

class MyDerivedFromNonAbstractComponent extends MyBaseNonAbstractComponent<MyDerivedComponentProps> {
    render() {
        return <div>Hello from id {this.props.id}</div>;
    }
}

// NOT WORKING EXAMPLE
abstract class MyBaseAbstractComponent<P> extends React.Component<P, any> {
    static getFactory() {
        return React.createFactory(this); // HERE IS THE COMPILER ERROR
    }
}

class MyDerivedFromAbstractComponent extends MyBaseAbstractComponent<MyDerivedComponentProps> {
    render() {
        return <div>Hello from id {this.props.id}</div>;
    }
}

ReactDOM.render(MyDerivedFromNonAbstractComponent.getFactory()({ id: "idForNonAbstract" }), document.getElementById("managed-content-for-non-abstract"));

ReactDOM.render(MyDerivedFromAbstractComponent.getFactory()({ id: "idForAbstract" }), document.getElementById("managed-content-for-abstract"));

================ ADDED 9/29/2016#2 =============

绝对是基类被标记为抽象,如果它有静态方法,并且该方法引用this,那么它实际上将取消引用派生的构造函数用于调用方法的类。

所以,如果我们有以下内容:

class BaseConcrete {
    static logWhoAmI() {
        console.log(`this is ${this}`);
    }
}

class DerivedConcrete extends BaseConcrete {
}

DerivedConcrete.logWhoAmI(); // This will log constructor of DerivedConcrete

abstract class BaseAbstract {
    static logWhoAmI() {
        console.log(`this is ${this}`);
    }
}

class DerivedAbstract extends BaseAbstract {
}

DerivedAbstract.logWhoAmI(); // This will log constructor of DerivedAbstract

因此,当基类是抽象的或不是抽象时,Typescript似乎不会对基类的静态方法中引用的this进行处理。

只是,不知何故,React.createFactory()方法的签名似乎在传递&#34; this&#34;时会以某种方式混淆。它抱怨是因为从表面上看,似乎它正在传递一个抽象方法的构造函数,这当然是非法的。但由于类本身是抽象的,运行时的this保证是派生类,React.createFactory应该可以正常工作。事实上,正如一位评论者指出的那样,如果你将参数转换为React.createFactoryany,它将在运行时正常工作。但在我看来这是黑客攻击。尽管如此欣赏这一讨论。

1 个答案:

答案 0 :(得分:1)

不能使用new直接实例化抽象类(这就是为什么会这样调用它们)。因此,您不能将它们用作React组件。但它们可以是其他组件的基类。

这就是TypeScript编译器静态检查的事情。由于抽象类没有new运算符,因此无法将其强制转换为ComponentClass。