Fortuna
Fortuna

Reputation: 609

How to properly assign generic props when using HoC?

So I have a component and this component gets passed to a HOC which should ehance the original component.

I declared a type for the props the component is receiving but I'm still getting the error "TS2741", which says:

Property 'auth' is missing in type '{}' but required in type 'AppProps'

I wrote a little example which you can see here: https://stackblitz.com/edit/react-ts-huaq8s

So my guess is, that TypeScript checks if props from the return function within withAuth has the properties declared via our type. This can only fail, since the properties we are checking for are added later (via <WrappedComponent ... />)

From my current knowledge my I guess is that I have to somehow tell TypeScript that the returned WrappedComponent should be checked for having P. But I don't know how to do that.

So obviously before I asked this question, I read a lot of online articles and a few questions here in the forum, but I still couldn't find the answer.

Can someone here help me?

Upvotes: 2

Views: 845

Answers (2)

apokryfos
apokryfos

Reputation: 40673

So this might be a bit complicated and I'm not 100% confident that this is really the correct way to go but here goes.

The goal here is to wrap a regular component which requires an auth property in a HOC which will provide that auth property. To do this you need your withAuth parameter to actually be a component which requires auth (as App does) and your result will be a component which does not.

Here's how you can achieve that:

type Omit<T,U> = Pick<T, Exclude<keyof T, U>>; // This is standard since 3.5

interface AuthProps {
  auth: TAuthProviderUtils
}

function withAuth<P extends AuthProps>(WrappedComponent: ComponentType<P>) : ComponentType<Omit<P,keyof AuthProps>> {
  return (props: Omit<P,keyof AuthProps>) => (
    <AuthContext.Consumer>
      {auth => <WrappedComponent {...props} auth={auth} />}
    </AuthContext.Consumer>
  )
}

// This needs auth
function App<AppProps>({ auth: { user } }) {
  return (
    <div>Hello App</div>
  )
}

const AppWithAuth = withAuth(App); // This does not need auth

Working example

Upvotes: 0

Gabor Szekely
Gabor Szekely

Reputation: 1238

I believe you just need to pass the AppProps type to withAuth, otherwise the generic you declared is not being used.

i.e.:

const AppWithAuth = withAuth<AppProps>(App)

Is this what you are looking for?

https://stackblitz.com/edit/react-ts-uxhgql?file=index.tsx

Upvotes: 1

Related Questions