Home > OS >  how to type a higher-order NextPage component
how to type a higher-order NextPage component

Time:09-20

I have a higher order component (HOC) that I use for auth purposes. I am converting this to a TypeScript friendly component. This is what I currently have:

import { NextPage } from 'next';
import { useAccount } from 'wagmi';

import { useAppSelector } from '../../hooks';
import EmptyState from '../EmptyState/EmptyState';

const withAuth = Component => {
  const AuthenticatedComponent: NextPage = () => {
    const currUser = useAppSelector(state => state.auth);
    const { isConnected } = useAccount();
    {
      return currUser.address && isConnected ? <Component /> : <EmptyState />;
    }
  };

  return AuthenticatedComponent;
};

export default withAuth;

And how I'd normally call it:

const Proposal: NextPage<{ proposalTags: ProposalTag[] }> = ({ proposalTags }) => { /** code here **/}

export default withAuth(Proposal);

The problem I'm having is the linter is complaining `Parameter 'Component' implicitly has an 'any' type.

I am not entirely sure how to type withAuth in this case for the Component argument.

I want to be able to pass it an instance of NextPage, which may or may not contain an assortment of props of different types of their own as you can see an example of my Proposal page above.

CodePudding user response:

You can use a generic to infer the prop types, then in the new component, pass those props to the component:

import { ComponentType } from "react";

function withAuth<P>(Component: ComponentType<P>) {
  const AuthenticatedComponent: NextPage<P & JSX.IntrinsicAttributes> = (props) => {
    const currUser = useAppSelector(state => state.auth);
    const { isConnected } = useAccount();
    {
      return currUser.address && isConnected ? <Component {...props} /> : <EmptyState />;
    }
  };

  return AuthenticatedComponent;
};

We need JSX.IntrinsicAttributes in case the component is a "built-in" like div, p, etc.

Playground

  • Related