0

I'm trying to implement a HOC in React and TypeScript but am getting a type error.

Here's the HOC:

import * as React from "react";

interface IProps {
  loading: boolean;
}

const withLoader = <P extends object>(
  Component: React.ComponentType<P>
): React.ComponentType<P & IProps> => ({ loading, ...props }: IProps) =>
  loading ? (
    <div className="overlay">
      <div className="loader" />
    </div>
  ) : (
    <Component {...props} />
  );
export default withLoader;

The version of the react types are:

"devDependencies": {
  "@types/react": "^16.7.18",
  "@types/react-dom": "^16.0.11",
  ...
}

The version of react is:

"dependencies": {
  "react": "^16.7.0",
  "react-dom": "^16.7.0",
  ...
}

The error I'm getting is:

Type '{}' is not assignable to type 'P'.ts(2322)

enter image description here

Has any one got any ideas?

1 Answer 1

1

It seems you have a type mismatch: your HOC has a return type of: React.ComponentType<P & IProps> but the function you're actually returning is of type (props: IProps) => React.ReactNode. If you made it (props: P & IProps) => React.ReactNode it would stop complaining. That said, they way I would type this HOC would be:

function withLoader<P extends IProps>(Component: React.ComponentType<P>) {
  const Inner: React.FC<P> = props => { // the return type is inferred by the compiler
    if (props.loading) {
      return (
        <div className="overlay">
          <div className="loader" />
        </div>
      )
    }
    return <Component {...props} />
  }

  return Inner // return type is React.FC<P>
}

This will keep the loading prop on the component although it would always be false once it reaches your component.

Final thought: I've found myself moving away from HOCs because they are difficult to type. If you care about type safety you might prefer to just use a render prop (maybe not for this use case) or handle it manually in your component. It might be more verbose but it's much easier to type and its more explicit. My opinion: HOC's are not the easiest things to get right in TypeScript so I use them very sparingly.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.