TypeScript 3: JSX element type 'Component' does not have any construct or call signatures. [2604]

后端 未结 5 739
挽巷
挽巷 2021-02-07 10:06

I\'m trying to pass a variable of type React.Component (or React.FunctionComponent) into a Route, like this:

import React from \'react\';
import { Route } from \         


        
相关标签:
5条回答
  • 2021-02-07 10:11

    I have encountered this a couple of times. Try these:

    1. Type your PrivateRoute as React.FC<Props>
    2. Type your incoming component as React.ElementType

    The ultimate truth about React types comes from the docs

    Edit: React.ReactType (deprecated) -> React.ElementType

    0 讨论(0)
  • 2021-02-07 10:19

    This is late but in case someone didn't want a solution but an explanation, let's talk about this error using an example to demonstrate it

    function PaymentPage(){
      
       return <div>Payment Page</div>
    }
    
    

    say we want to create a dynamic payment form, if the query parameter is with=stripe so we assume he wants to pay with stripe, if it's with razorpay we assume it, ...etc.

    we then do something like

    function PaymentPage(){
       const router = useRouter;
       const {with} = router.query;
       let GatewayComponent: Gateway | null = null;
       switch(with){
         case 'stripe':
           return <StripeGateway/>
         case 'razorpay':
           return <RazorpayGateway/>
       }
       return <GatewayComponent/>
    }
    

    Running this, we get

    JSX element type 'Component' does not have any construct or call signatures.
    

    What happens?

    What are component?

    • Constructors that return elements of type JSX.Element

    So?

    • We are not returning a constructor, we are returning a Constructor call, it's the same as assuming that GatewayComponent is a constructor, but it's not, it's a variable holding JSX

    So basically, expects x to be a constructor of any type, either a function or a class, if it's a function, the function is the render function, if it's a class, it needs a render method.

    Back to our problem

    function PaymentPage(){
       const router = useRouter;
       const {with} = router.query;
       let gateway: Gateway | null = null;
       switch(with){
         case 'stripe':
           return <StripeGateway/>
         case 'razorpay':
           return <RazorpayGateway/>
       }
       return <React.Fragment> {gateway} </React.Fragment>
    }
    

    Because gateway holds JSX, not a constructor that returns JSX

    What if you want to use it as a component?

    function PaymentPage(){
       const router = useRouter;
       const {with} = router.query;
       let GatewayComponent: Gateway | null = null;
       switch(with){
         case 'stripe':
           return () => <StripeGateway/>
         case 'razorpay':
           return () => <RazorpayGateway/>
       }
       return <GatewayComponent/>
    }
    

    Now it's a constructor, we can use it as a component right now.

    Formally, you pass the constructor and not the instance.

    0 讨论(0)
  • 2021-02-07 10:21

    Even later to the party, but what worked for me is this:

    interface PrivateRouteProps extends Omit<RouteProps, "component"> {
      component: React.ElementType;
      // any additional vars
    }
    
    PrivateRoute: React.FC<PrivateRouteProps> = ({
      component: Component,
      ...rest
    }) => {
    // render code
    }

    0 讨论(0)
  • 2021-02-07 10:30

    I was able to resolve the error by typing my component as follows:

    ...
    export function withApollo (PageComponent: () => JSX.Element) {
    const WithApollo = <T extends object>(props: T) => {
    ...
    
    0 讨论(0)
  • 2021-02-07 10:34

    Late to the party, with "@types/react-router-dom": "^4.3.4" and "@types/react": "16.9.1", and if you're using RouteProps, you will probably get the same error.

    JSX element type 'Component' does not have any construct or call signatures. [2604]

    That's because, in the RouteProps interface, the component is defined as optional, hence it might be undefined.

    export interface RouteProps {
      location?: H.Location;
      component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
      render?: ((props: RouteComponentProps<any>) => React.ReactNode);
      children?: ((props: RouteChildrenProps<any>) => React.ReactNode) | React.ReactNode;
      path?: string | string[];
      exact?: boolean;
      sensitive?: boolean;
      strict?: boolean;
    }
    

    Simply check for if the component is falsy will fix it.

    function PrivateRoute({ component: Component, ...rest }: RouteProps) {
      if (!Component) return null;
      return (
        <Route
          {...rest}
          render={props =>
            fakeAuth.isAuthenticated ? (
              <Component {...props} />
            ) : (
              <Redirect
                to={{
                  pathname: "/login",
                  state: { from: props.location }
                }}
              />
            )
          }
        />
      );
    }
    
    0 讨论(0)
提交回复
热议问题