Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React & TypeScript HOCs - why I get Type '{}' is not assignable to Type P?

I hit the wall while coding along with Learning React with TypeScript book. I surrendered and copy pasted code directly from the book, but compiler is still unhappy

My current workaround is to provide 'any' value, instead of IProps, but this is a cheap hack.

Not working code:

import * as React from 'react';

interface IProps {
  loading: boolean;
}

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

 export default withLoader;

Working code (I only changed IProps to any):

import * as React from 'react';

interface IProps {
  loading: boolean;
}

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

 export default withLoader;

In not working code, I get Type '{}' is not assignable to Type P error. I would like to solve this issue, as it would help me understand what is going on. I am total beginner at TypeScript!

like image 844
Rafał Bagrowski Avatar asked Jan 01 '23 07:01

Rafał Bagrowski


1 Answers

Starting with 3.2 the behaviour of the spread operator for generics has changed. Apparently the type of props gets erased as a negative side effect, but you can work around that by casting it back to P using {...props as P} when spreading back into the wrapped component.

like image 102
Christian Ivicevic Avatar answered Jan 14 '23 04:01

Christian Ivicevic