Chris B.
Chris B.

Reputation: 5763

Can't write higher order components in Typescript: JSX Element type does not have any construct or call signatures

Yes, I realize this question has been asked, but none of the answers I found resolved this. I am writing a simple higher order component in Typescript to verify authorization before rendering a component. So far it looks like this:

export function withAuth(Component: React.ComponentType) {

    if (!Component) return null;

    useEffect(() => {
        verifyToken().then(res => console.log(res))
    }, []);

    return (
        <Component/>
    )
}

I have a larger FunctionComponent called EditorContainer that I pass to the HOC and export from its own file: export default withAuth(EditorContainer);

Which is imported as import EditorContainer from "./modules/Editor/containers/EditorContainer"; and throws this error.

I have tried:

  1. Passing the HOC a new instance of the component instead of its constructor. This throws a different error.
  2. Changing or removing all types. The error remains.
  3. Updating react, react-dom, @types/react and @types/react-dom.
  4. Capitalizing withAuth as WithAuth (I'm running out of ideas here).
  5. Removing the component from its original location (being rendered by a React Router route). Makes no difference.

It seems like writing a higher order component in TypeScript is disallowed.

Upvotes: 3

Views: 2118

Answers (2)

locomotif
locomotif

Reputation: 151

see my comment as to why your solution is working; however you can remove the extra function.

export function withAuth(Component: React.ComponentType) {

    if (Component == null) { return () => null; }
    return () => {
        useEffect(() => {
            verifyToken().then(res => console.log(res))
        }, []);

        return (
            <Component/>
        )
    };
}

Upvotes: 1

Chris B.
Chris B.

Reputation: 5763

Fixed this by defining the HOC as a curried function. :

export const withAuth = (Component: ComponentType<any>) => (props: any) => {

    const AuthWrapper: FunctionComponent = (props: any) => {
        const [auth, setAuth] = useState<any>(null);

        useEffect(() => {
            verifyToken().then(res => {
                console.log(res);
                setAuth(res);
            })
        }, []);

        if (!auth) return <Result
            status="403"
            title="403"
            subTitle="Sorry, you are not authorized to access this page."
            extra={<Link to="/"><Button type="primary">Back Home</Button></Link>}
        />;

        return (
            <Component {...props} authUser={auth}/>
        )
    }

    return <AuthWrapper {...props}/>;

};

Literally no idea why this works, so I guess the question's not really answered. How should explicitly returning a function be any different from returning a FunctionComponent which... is a function? Especially after stripping the types, I'm not clear on what the difference is.

Upvotes: 1

Related Questions