Xizam
Xizam

Reputation: 718

Passing generics to a component wrapped in a HOC

I have an implementation of the ApolloGraphQL Query component.

When using the Apollo client Query component, typings can be passed as such:

import * as ApolloTypes from './__generated__/GetSubreddit';

 <Query<ApolloTypes.GetSubreddit, ApolloTypes.GetSubredditVariables>
      query={GET_SUBREDDIT}
      variables={{ name: selectedSubreddit }}
    >
...
</Query>

I have my own component which implements the Apollo Query component. Amongst other things, it adds some headers to each query. I want to be able to pass it typings in the same way as the normal query component, which is easy to do without the connect higher order component from "react-redux". I can't figure out how to pass the generics through the HOC. Any advice?

const GraphqlQuery = <T, TVariables = OperationVariables>(props: PropsType) => {
  const { query, variables, children, user, ...rest } = props;
  if (!user) return null;

  return (
    <Query<T, TVariables>
      query={query}
      variables={variables}
      context={{
        headers: {
          "X-User-Id": user.id,
        },
      }}
      {...rest}
    >
    ...
    </Query>
  );
};


const mapStateToProps = ({ user }: { user: IUserState }) => ({
  user,
});
export default connect(
  mapStateToProps,
  {}
)(GraphqlQuery);

Upvotes: 1

Views: 551

Answers (1)

Donovan Hiland
Donovan Hiland

Reputation: 1499

There are 2 options that I can think of that you can do to achieve this:

  1. Cast the export:

In your case it might be a little extra tricky but something like this might work as long as the HOC doesn't require any props. If it does you'll have to change the type you're casting as.

export default connect(
  mapStateToProps,
  {}
)(GraphqlQuery) as typeof GraphqlQuery
  1. factory
export const createGraphqlQuery = <T, TVariables = OperationVariables>() => {
  const GraphqlQuery = (props: PropsType) => {
    const { query, variables, children, user, ...rest } = props;
    if (!user) return null;

    return (
      <Query<T, TVariables>
        query={query}
        variables={variables}
        context={{
          headers: {
            "X-User-Id": user.id,
          },
        }}
        {...rest}
      >
      ...
      </Query>
    );
  };


  const mapStateToProps = ({ user }: { user: IUserState }) => ({
    user,
  });
  return connect(
    mapStateToProps,
    {}
  )(GraphqlQuery)
};

Usage:

const GraphqlQuery = createGraphqlQuery<{}, {}>();

<GraphqlQuery ... />

There are definitely tradeoffs to each.

Upvotes: 4

Related Questions