Vasyl Butov
Vasyl Butov

Reputation: 474

How to pass children type to props of HOC react

I am new to TypeScript and I am struggling to write HOC with typecheck. Here's my HOC:

import React from 'react';
import Firebase from './Firebase';

export type FirebaseType = Firebase;

interface OwnProps {
  firebase: typeof Firebase;
}

const FirebaseContext = React.createContext(new Firebase());

export const withFirebase: React.FC = <T extends OwnProps>(
  Component: React.ComponentType<T>,
): React.ComponentType<T> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase: FirebaseType) => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);

export default FirebaseContext;

It throws an error:

Type '(Component: React.ComponentType) => React.ComponentType' is not assignable to type 'FC<{}>'. Types of parameters 'Component' and 'props' are incompatible. Type '{ children?: ReactNode; }' is not assignable to type 'ComponentType'. Type '{ children?: ReactNode; }' is not assignable to type 'FunctionComponent'. Type '{ children?: ReactNode; }' provides no match for the signature '(props: PropsWithChildren, context?: any): ReactElement ReactElement Component)> | null) | (new (props: any) => Component<...>)> | null'.ts(2322)

I have absolutely no idea how to move on with this code or how to make it work.

Any thoughts?

Upvotes: 0

Views: 2644

Answers (1)

helloitsjoe
helloitsjoe

Reputation: 6529

Here's what that error means:

In your type definition, you're expecting withFirebase to have the same type signature as a function component (React.FC), which takes in props and returns a React element (or null).

However, that's not what you want from a HOC, you want it to take in a Component (React.ComponentType) and return a Component (React.ComponentType).

This should work:

type HOC = (Component: React.ComponentType) => React.ComponentType;
// Or, if you want to be more specific:
// type HOC = <T extends OwnProps>(Component: React.ComponentType<T>) => React.ComponentType<T>

export const withFirebase: HOC = <T extends OwnProps>(
  Component: React.ComponentType<T>,
): React.ComponentType<T> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase: FirebaseType) => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);

Or you can also just omit the HOC type, and TypeScript will infer the correct type from the function definition.

Upvotes: 4

Related Questions