以下使用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.createFactory
到any
,它将在运行时正常工作。但在我看来这是黑客攻击。尽管如此欣赏这一讨论。
答案 0 :(得分:1)
不能使用new
直接实例化抽象类(这就是为什么会这样调用它们)。因此,您不能将它们用作React组件。但它们可以是其他组件的基类。
这就是TypeScript编译器静态检查的事情。由于抽象类没有new
运算符,因此无法将其强制转换为ComponentClass。