Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: JSX element type does not have any construct or call signatures

I'm working with React 16.2.0, TypeScript 2.7.1, and any is not allowed as a type.

The main component:

// index.js

import * as React from 'react'
import Page from './page'
import i18n from '../i18n'

import PageContent from '../components/pageContent'
import withMoreInfo from '../hoc/withMoreInfo'

class Home extends React.Component {
  render () {
    return <Page title={ i18n.t('home.title') }>
      <PageContent />
    </Page>
  }
}

export default withMoreInfo(Home)

The hoc file:

import * as React from 'react'

export default function withMoreInfo<T> (Wrapped: T) {
  return class WithMoreInfo extends React.Component<{ asPath: string }> {
    static async getInitialProps ({ asPath }: { asPath: string }) {
      return { asPath }
    }

    render () {
      const { asPath } = this.props
      const language = asPath.indexOf('/ro') === 0 ? 'ro' : 'en'
      return <Wrapped language={ language } pathname={ asPath } />
    }
  }
}

I can't solve this error: error #TS2604: JSX element type 'Wrapped' does not have any construct or call signatures.

enter image description here

Any hint is very much appreciated. Thanks, Paul

like image 661
Paul Avatar asked Feb 24 '18 16:02

Paul


2 Answers

You need to tell the compiler that the parameter is a constructor function and that returns a React component with the properties language and pathname

function withMoreInfo<T extends React.Component<{ language: string, pathname: string }, any>>(Wrapped: new (props: { language: string, pathname: string }, context?: any) => T) {
    return class WithMoreInfo extends React.Component<{ asPath: string }> {
        static async getInitialProps({ asPath }: { asPath: string }) {
            return { asPath }
        }

        render() {
            const { asPath } = this.props
            const language = asPath.indexOf('/ro') === 0 ? 'ro' : 'en'
            return <Wrapped language={language} pathname={asPath} />
        }
    }
}
// The component must have properties language and pathname and only those
class Home extends React.Component<{ language: string, pathname: string }> {
    render() {
        return <div />
    }
}

export default withMoreInfo(Home)

In your original version when you invoke withMoreInfo(Home), T would have indeed been a react component, however you could have just as well invoked withMoreInfo(1) since T was in no way constrained. The generic function must be correct for any type that is passed to it, so the compiler considered T as being possibly anything and so it could reliably say nothing about it. The solution is to let the compiler know, that the Wrapped parameter is a constructor of a react component, namely any react component T that has as properties { language: string, pathname: string }. A constructor function has a similar signature declaration to a regular function, just with the new keyword, hence new (props: { language: string, pathname: string }, context?: any) => T

like image 53
Titian Cernicova-Dragomir Avatar answered Oct 19 '22 22:10

Titian Cernicova-Dragomir


Putting an answer here because it is relevant to the error in general.

I was missing new inside the type definition.

some-js-component.d.ts file:

import * as React from "react";

export default class SomeJSXComponent extends React.Component<any, any> {
    new (props: any, context?: any)
}

and inside the tsx file where I was trying to import the untyped component:

import SomeJSXComponent from 'some-js-component'

...inside render()
   return (
        <React.Fragment>
            <SomeJSXComponent withProps={asdf} />
        </React.Fragment>
   );
like image 22
jmunsch Avatar answered Oct 19 '22 21:10

jmunsch