首页 > 解决方案 > 打字稿类型定义:TS2604:JSX 元素类型“某物”没有任何构造或调用签名

问题描述

我在“File1”中有一个抽象类:

// File1.tsx

import * as React from 'react';

export interface IProps {
  prop1: string;
  prop2: number;
}

export abstract class Something extends React.Component<IProps> {
  public typeName: string;
}

然后,在其他文件(File2)中,我定义了从抽象类Something扩展的无限类:

// File2.tsx

import { Something } from './File1';

export class Something1 extends Something {
  public typeName: string = 'Type1';

  public render() {
    return <div>Something 1</div>
  }
}

export class Something2 extends Something {
  public typeName: string = 'Type2';

  public render() {
    return <div>Something 2</div>
  }
}

现在,这是我的问题:在第三个文件中,我导入之前定义的类(Something1 或 Something2),然后将此类传递给 2 个不同的组件:ReadProperty 和 RenderComponent。在第一个组件中,我需要访问类的属性 typeName 并做一些事情,在第二个文件中,我需要渲染该类:

// File3.tsx

import { Something } from './File1';
import { Something1, Something2 } from './File2';

interface IReadProperty {
  something: Something;
};

const ReadProperty: React.SFC<IReadProperty> = ({ something }) => {
  // here i can access to property typeName. No problem here.

  something.typeName // Type1 | Type2 | ... Infinite

  ...do some stuff
}


interface IRenderComponent {
  something: Something;
}

const RenderComponent: React.SFC<IRenderComponent> = ({ something }) => {
  // i need do some stuff here before render "something" component
  // here i get an error when i try render the component
  return <something />;
}


const Main: React.SFC = () => {
  return (
    <div>
      <ReadProperty something={Something1} />
      <RenderComponent something={Something1} />
    </div>
  );
}

但是当我尝试在 RenderComponent 中渲染组件时,出现以下错误:TS2604:JSX 元素类型“某物”没有任何构造或调用签名。

这里有什么问题?我将类型'something'定义为抽象类Something,因为我可以定义从Something扩展的无限类,所以我不能定义使用:something:Something1 | 东西2 | 东西50 ...;

这是我尝试做的一个例子:https ://codesandbox.io/s/18yzvkx8jj

标签: javascriptreactjstypescripttypes

解决方案


问题在于,在您的定义中IRenderComponent,您说的something是 的实例Something而您想要的是构造函数类型。另一件事是,当您尝试使用小写名称实例化组件时,React 通常会抱怨。尝试这个:

interface IRenderComponent {
  Something: new (props: IProps) => Something1;
};

const RenderComponent: React.SFC<IRenderComponent> = ({ Something }) => {
  return <Something prop1="foo" prop2={3} />;
}

对于IReadProperty,看起来您确实想要一个实例Something(因为您想要访问typeName,它是一个实例属性)。但是,您实际上不能传递实例化的组件:

<ReadProperty something={<Something1 prop1="" prop2={3} />;} /> //Error

这是因为<Something1 ... />它实际上不是一个实例Something1- 它是一个JSX.Element. 您可以传递 的实例Something1,如下所示:

<ReadProperty something={new Something1({prop1: "", prop2: 3})} />

但我想这不是你想要的,因为你实际上不能在渲染中使用生成的实例。

解决问题的最佳方法IReadProperty取决于您实际想要完成的任务。一般来说,React 更倾向于组合而不是继承和反射,因此可能更容易考虑如何通过从基础组件开始并组合它们或使用高阶组件来实现您的目标。


推荐阅读