Search code examples
reactjstypescriptreact-typescripttsx

React component in TypeScript if passed as parameter and assigned to variable; TS2604: JSX element type does not have any construct or call signatures


I'm trying to hanlde props of passed React Element in Factory but I cannot because I receive typescript error:

TS2604: JSX element type 'this.extraBlock' does not have any construct or call signatures.

My Child component:

interface BlockTitleType {
  title: string,
  children?: React.ReactNode
}

const MainContactBlock: React.FC<BlockTitleType> = (e: BlockTitleType) => <div>{e.title}</div>;

My Parent component:

const factory = new TabBlockFactory(MainContactBlock);

const ContactBlocks: React.FC = () => <>factory.createBlock('test title')}</>

My factory:

interface BlockType {
  title: string
}

class TabBlockFactory {
  private mainBlock: React.ReactNode;

  constructor(mainBloc: React.FC) {
    this.mainBlock = mainBloc;
  }

  createBlock = ({title}: BlockType) => {
// the error occurs here: 
// TS2604: JSX element type 'this.extraBlock' does not have any construct or call signatures.
   return <this.mainBlock title={title}/>
  }
}

it works only with any type, but it's an antipatern :(

Update:

I also tried types as React.Component, React.ReactElement, JSX.Elements

I've tried all 3 fixes from @Yuval:

  1. Has no effect - renamed class variable this.mainBlock -> this.MainBlock;

  2. Has no effect - introduced intermediate variable

const Component = this.mainBloc;
return <Component title={title} />;
  1. Successfully helped me - private MainBlock: React.ComponentType<BlockTitleType>; as @Yuval proposed.

Solution

  • TLDR: working sandbox link

    So there is a few problems with your code:

    1. you are using the type React.ReactNode to represent a component, and it doesn't work. I recommend that to represent a React Component you use React.ComponentType<PROPS>. So in your case in will be ComponentType<BlockTitleType>

    2. the line <this.mainBlock /> is problematic, react doesn't like Components that do not start with an Upper case and also its an access to a this attribute at the same time, so separate that into 2 lines like so:

    const Component = this.mainBloc;
    return <Component title={title} />;
    
    1. other than that I added some small syntax fixes and small improvements

      • quick assignment and declaration in the Factory class
      • missing { in ContactBlocks