Skip to content

JSX element type does not have any construct or call signatures in v3.2.0-rc #28631

Closed

Description

@rexpan

TypeScript Version: 3.2.0-rc, 3.2.1

Code

import * as React from "react";
import { Component, ReactType} from "react";
function App(props:{component:ReactType}) {
  const Comp: ReactType = props.component
  return (<Comp />)
}

Expected behavior:
Should output normal as TypeScript 3.1.6

Actual behavior:
TS2604: JSX element type 'Comp' does not have any construct or call signatures.

Activity

  1. Jessidhia commented on Nov 23, 2018

    @Jessidhia

    This is missing the rest of the error message but, to be sure, make sure you are on the latest version of @types/react and that there are no duplicates of it left around in your node_modules or lock file.

    EDIT: you probably mean to use ComponentType and not ReactType

  2. rexpan commented on Nov 23, 2018

    @rexpan
    Author

    @Kovensky

    I have make sure using the latest @types/react 16.7.7 and no duplicates @types/react in yarn.lock.
    If the issue is because of duplication of @types/react, it will return the error Duplication of definition ....

    I revert back to "typescript": "^3.1.6" then it work normally.

  3. goloveychuk commented on Nov 30, 2018

    @goloveychuk

    Typescript 3.2.1

    other example

    interface P1 {
      p?: boolean
      c?: string
    }
    
    interface P2 {
      p?: boolean
      c?: any // if you replace c with string, error goes away
      d?: any
    }
    
    declare var C: React.ComponentType<P1> | React.ComponentType<P2>
    
    
    const a = <C p={true} /> // element does not have any ...

    It looks like, the problem is related to new "nullable discriminants" changes. Looks like ts can't find common interface for those types.
    Other example

    interface P1 {
      p?: any
      c?: string // remove this and it's ok
    }
    
    interface P2 {
      p?: boolean
    }
  4. layershifter commented on Dec 6, 2018

    @layershifter

    We have a similar problem, quick example:

    import * as React from 'react'
    
    //
    // Types
    //
    
    interface Config<P> {
      ElementType: React.ReactType<P>
    }
    
    interface EmptyProps {
    }
    
    interface Props {
      a?: string
    }
    
    type HProps = {
      configEmpty: Config<EmptyProps>,
      config: Config<Props>
    }
    
    //
    // Component
    //
    
    const H: React.FC<HProps> = ({ config, configEmpty }) => {
      const A: React.ReactType<EmptyProps> = configEmpty.ElementType // assigned
      const B: React.ReactType<EmptyProps> = 'div' // assigned
    
      const C: React.ReactType<Props> = config.ElementType // assigned
      const D: React.ReactType<Props> = 'div' // in this case assignment failed
    
      return (
        <div>
          <A/> {/* TS2604: JSX element type 'A' does not have any construct or call signatures. */}
          <B/>
    
          <C/>
          <D/>
        </div>
      )
    }
    
    export default H

    I see this behaviour as completely invalid, because A and B have the same types. In the same time, B and D have similar types, but D is not assignable 🤔

    Code in repo: https://github.com/layershifter/ts-issue

  5. Jessidhia commented on Dec 6, 2018

    @Jessidhia

    They do not, because you're using const. The type of A is typeof configEmpty.ElementType, but the type of B is 'div'. Using lets will show the same behavior on both.

  6. layershifter commented on Dec 6, 2018

    @layershifter

    @Kovensky what about A and C? Why C works while A fails with does not have any construct error?

  7. Jessidhia commented on Dec 6, 2018

    @Jessidhia

    That is because I improved the type of ReactType to exclude components that would not be able to receive the props you are giving it. Because none of the DOM elements can receive { a: string | undefined }, they are all excluded, and only function/class components are still allowed to be assigned to it.

  8. layershifter commented on Dec 6, 2018

    @layershifter

    @Kovensky thank you 👍 Now the issue with assignment is clear for me, but what about this?

    import * as React from 'react'
    
    //
    // Types
    //
    
    interface Config<P> {
      ElementType: React.ReactType<P>
    }
    
    interface Empty {}
    interface Props { a?: string }
    
    type HProps = {
      configEmpty: Config<Empty>,
      config: Config<Props>
    }
    
    //
    // Component
    //
    
    const H: React.FC<HProps> = ({ config, configEmpty }) => {
      const A: React.ReactType<Empty> = configEmpty.ElementType // is React.ReactType<Empty>
      const B: React.ReactType<Empty> = 'div' // is string
      const C: React.ReactType<Props> = config.ElementType // is React.ReactType<Props>
    
      return (
        <div>
          {/* React.ReactType<Empty> */} <A/> {/* <--- TS2604: JSX element type 'A' does not have any construct or call signatures. */}
          {/* React.ReactType<Empty> */} <B/>
          {/* React.ReactType<Props> */} <C/>
        </div>
      )
    }
    
    export default H

    A and B has the same obviously defined types, why A fails? It's really confusing thing.

  9. azizhk commented on Dec 6, 2018

    @azizhk
    Contributor

    I would probably say Vien Luong (@rexpan) and Vadym Holoveichuk (@goloveychuk)'s error is similar to #28795 and #28768 based on conditional JSX constructor.

  10. weswigham commented on Dec 10, 2018

    @weswigham
    Member

    Hm, so the issue is that ReactType<any> returns a union of every builtin jsx tag (plus ComponentType<any>, but that part's not problematic), and the signatures for those components do not trivially simplify (there is not a signature that perfectly encompasses all the others). This, too, relies on #7294 to be fixed. On the plus side, the underlying change needed to fix for all these JSX issues that get reported is the same.

    For context, we effectively manufacture a type like this:

    declare const JsxSigs: {[K in keyof JSX.IntrinsicElements]: ((props: JSX.IntrinsicElements[K]) => JSX.Element)}[keyof JSX.IntrinsicElements];

    which ends up as being a union of a ton of unique signatures.

  11. added
    BugA bug in TypeScript
    DuplicateAn existing issue was already created
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Dec 10, 2018
  12. 6 remaining items

  13. hegelstad commented on Mar 27, 2019

    @hegelstad
  14. TacB0sS commented on Mar 27, 2019

    @TacB0sS

    I might have misunderstood the thread, but I wanted to pass a reference of a jsx Element to another jsx element:

    export const AppWrapper = hot(module)((props: WrapperProps) => {
    
    	const MainApp = props.mainApp;
    	if (!MainApp)  // <-- JSX elements MUST start with upper case!!
    		throw new ImplementationMissingException("mainApp was not specified!!");
    
    	return (
    		<Router history={BrowserHistoryModule.getHistory()}>
    			<MainApp prop1={"value"}/>
    		</Router>)
    });

    Together with:

    export type WrapperProps = {
    	mainApp: React.ElementType<{prop1:string}>
    }
  15. orest22 commented on Apr 25, 2019

    @orest22

    Adam van der Kruk (@TacB0sS) For me the main trick was adding if condition. Looks like it doesn't matter whether you use React.ComponentType or React.ElementType

  16. ericmasiello commented on May 24, 2019

    @ericmasiello

    I'm not sure i understand the outcome of this. I have a similar error that I have not been able to resolve. Here is my use case:

    // Logo.tsx
    
    import classNames from 'classnames';
    
    interface Props extends React.HTMLAttributes<HTMLElement> {
      tag?: React.ReactType;
    }
    
    const Logo: React.SFC<Props> = props => {
      const { tag: Tag = 'div', className, ...rest } = props;
      return (
        <Tag
          className={classNames(styles.logo, className)}
          {...rest}
          dangerouslySetInnerHTML={{ __html: logo }}
        />
      );
    };
    

    and then I'm using it like such in another component like so:

    const Header: React.SFC<{}> = () => {
      return (
        <div>
          <Logo tag="h1" aria-label="Syn By Design: Eric Masiello's Portfolio" />
          Header online
        </div>
      );
    };
    

    When I run the compiler, i get this error:

    components/Logo.tsx:13:6 - error TS2604: JSX element type 'Tag' does not have any construct or call signatures.
    
    13     <Tag
            ~~~
    
    
    Found 1 error.
    

    Any ideas how to make this work?

  17. pinkbunny1 commented on Nov 22, 2019

    @pinkbunny1

    Instead of Component, use ComponentClass

  18. jedwards1211 commented on Dec 13, 2019

    @jedwards1211

    I got this error because I imported default but declared the corresponding export as named instead of default in the .d.ts file...confused me for awhile

  19. SARCASMOOO commented on Aug 12, 2020

    @SARCASMOOO

    Just wanted to add this here. Not sure if this was already said but if you are doing a hirer order component you want to use the type React.ComponentType

    . "https://flow.org/en/docs/react/types/#toc-react-componenttype"

  20. hellatan commented on Oct 5, 2020

    @hellatan

    Eric Masiello (@ericmasiello) I ended up using React.ElementType for a dynamically passed in component. My use case is basically the following:

    type Props = {
        heading: React.ElementType
    }
    const Header: FC<Props> = props => {
        const Header = props.heading ?? 'h2';
        return (
            <Header className="some-class"><children /></Header>
        )
    }
  21. ericmasiello commented on Oct 5, 2020

    @ericmasiello

    Eric Masiello (@ericmasiello) I ended up using React.ElementType for a dynamically passed in component. My use case is basically the following:

    type Props = {
    
        heading: React.ElementType
    
    }
    
    const Header: FC<Props> = props => {
    
        const Header = props.heading ?? 'h2';
    
        return (
    
            <Header className="some-class"><children /></Header>
    
        )
    
    }

    Cool! What version of Typescript and what version of @types/react do you have installed?

  22. hellatan commented on Oct 5, 2020

    @hellatan

    Eric Masiello (@ericmasiello)

    Cool! What version of Typescript and what version of @types/react do you have installed?

    TypeScript@3.9.7
    @types/react@16.9.49

  23. LuisDev99 commented on Nov 8, 2020

    @LuisDev99

    I solved this problem by doing any of these two things:

    Case 1:

    .d.ts file:

    declare module "foo" {
       interface PropFoo {
          propy: string;
       }
    
       class MyTypedComponent extends React.Component<PropFoo> { }
    }

    React:

    import MyTypedComponent from "foo";
    
    function AnotherComponent() {
    
       /* Notice in here we have to use the dot operator and reference the component */
       return <MyTypedComponent.MyTypedComponent /> 
    }

    Notice that, in order to use the newly typed component, we have to write MyTypedComponent.MyTypedComponent . This may be obvious to some people, but I wasted alot of time when all I had to do was to use the dot operator on the import and reference the component.

    Case 2 [just another way of writing Case 1]:

    .d.ts file:

    declare module "foo" {
       interface PropFoo {
          propy: string;
       }
    
       export default class MyTypedComponent extends React.Component<PropFoo> { } //Notice the export default in here
    }

    React:

    import MyTypedComponent from "foo";
    
    function AnotherComponent() {
    
       /* Since this component is default exported, no need to use the dot operator */
       return <MyTypedComponent /> 
    }

    Soo, basically, check your exports, default exports, and imports and make sure you are referencing correctly.

    I'm very sorry for my English and I hope this helps.

  24. zhuxchong commented on Nov 25, 2020

    @zhuxchong

    for me the solution was:

    export type WrapperProps = {
    	mainApp: React.ElementType
    }
    

    niu b

  25. mancoxu commented on Jan 22, 2021

    @mancoxu

    for me the solution was:

    export type WrapperProps = {
    	mainApp: React.ElementType
    }
    

    niu b

    ni zhe hui da ye nb haha

  26. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: JSX/TSXRelates to the JSX parser and emitterDuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions