9
votes

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

2

2 Answers

6
votes

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

1
votes

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>
   );