Apollo Client return type in Typescript
Asked Answered
M

1

9

I am trying to build a simple function inside a class that returns an Apollo Client. Here is my code:

import appConfig from 'config/app-config';
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import LocalStorageKeys from 'constants/local-storage-keys';
import { setContext } from '@apollo/client/link/context';

export class ApolloClientServiceImpl {
  private cache: InMemoryCache;
  constructor() {
    this.cache = new InMemoryCache();
  }

  createApolloClient(idToken: string): unknown {
    const httpLink = createHttpLink({
      uri: appConfig.hasura.url,
    });
    const authLink = setContext((_, { headers }) => {
      let bearerToken = localStorage.getItem(LocalStorageKeys.TOKEN);
      if (idToken) {
        bearerToken = idToken;
      }
      return {
        headers: {
          ...headers,
          authorization: bearerToken ? `Bearer ${bearerToken}` : '',
        },
      };
    });
    return new ApolloClient({
      link: authLink.concat(httpLink),
      cache: this.cache,
    });
  }
}

My problem lies in the return type of the createApolloClient function. If I set it to ApolloClient<InMemoryCache> and in the return statement do something like this:

return new ApolloClient<InMemoryCache>({
      link: authLink.concat(httpLink),
      cache: this.cache,
    });

Then I get the following error:

Type 'InMemoryCache' is not assignable to type 'ApolloCache<InMemoryCache>'.
  Types of property 'restore' are incompatible.
    Type '(data: NormalizedCacheObject) => InMemoryCache' is not assignable to type '(serializedState: InMemoryCache) => ApolloCache<InMemoryCache>'.
      Types of parameters 'data' and 'serializedState' are incompatible.
        Type 'InMemoryCache' is not assignable to type 'NormalizedCacheObject'.
          Index signature is missing in type 'InMemoryCache'.ts(2322)

There is very little documentation about this topic on the Apollo client docs, thus my question is, what is the correct return type of this function?

EDIT: If I stay with only:

    return new ApolloClient({
      link: authLink.concat(httpLink),
      cache: this.cache,
    });

And change the return type to ApolloClient<NormalizedCacheObject> then this fixes everything the error. Thanks to Alluan Hadad.

Math answered 28/9, 2020 at 0:12 Comment(3)
new ApolloClient<InMemoryCache> is bad. Should be new ApolloClientCallie
@AluanHaddad turned out that this fixed the issue. Thanks a lot!Math
No problem. Specifying explicit type arguments, especially when there are values being passed, is an anti pattern. Correct typescript leverages type inference as much as possibleCallie
S
11

check out my class. The return type is ApolloClient<NormalizedCacheObject>

import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { FragmentMatcher } from "apollo-client/core/LocalState";
import { ApolloLink } from "apollo-link";
import { onError } from "apollo-link-error";
import { HttpLink } from "apollo-link-http";

enum EApolloCLientCredentials {
    DEFAULT_OMIT = "omit",
    INCLUDE = "include",
    SAME_ORIGIN = "same-origin",
}

class ClsApolloClient {
    private _httpLink: HttpLink;
    private _credentials: EApolloCLientCredentials;
    private _fragmentMatcher: FragmentMatcher | undefined;
    private _graphqlServerUrl: string;
    private _cacheInMemoryRules: Record<string, any>;
    private _apolloClient: ApolloClient<NormalizedCacheObject>;

    constructor(
        graphqlServerUrl: string,
        credentials: EApolloCLientCredentials = EApolloCLientCredentials.DEFAULT_OMIT,
        fragmentMatcher?: FragmentMatcher,
        cacheInMemoryRules: Record<string, any> = {}
    ) {
        this._graphqlServerUrl = graphqlServerUrl;
        this._credentials = credentials;
        this._fragmentMatcher = fragmentMatcher;
        this._cacheInMemoryRules = cacheInMemoryRules;

        this._apolloClient = this.initApolloClient();
    }

    get apolloClient(): ApolloClient<NormalizedCacheObject> {
        return this._apolloClient;
    }

    get httpLink(): HttpLink {
        return this._httpLink;
    }

    get cacheInMemoryRules(): Record<string, any> {
        return this._cacheInMemoryRules;
    }
    set cacheInMemoryRules(cacheInMemoryRules: Record<string, any>) {
        this._cacheInMemoryRules = cacheInMemoryRules;
        this._apolloClient = this.initApolloClient();
    }

    get credentials(): EApolloCLientCredentials {
        return this._credentials;
    }

    set credentials(credentials: EApolloCLientCredentials) {
        this._credentials = credentials;
        this._apolloClient = this.initApolloClient();
    }

    get fragmentMatcher(): FragmentMatcher | undefined {
        return this._fragmentMatcher;
    }

    set fragmentMatcher(fragmentMatcher: FragmentMatcher | undefined) {
        this._fragmentMatcher = fragmentMatcher;
        this._apolloClient = this.initApolloClient();
    }

    private initApolloClient(): ApolloClient<NormalizedCacheObject> {
        const errorLink = onError(({ graphQLErrors, networkError }) => {
            if (graphQLErrors)
                graphQLErrors.forEach(({ message, locations, path }) =>
                    console.log(
                        `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
                    )
                );

            if (networkError) console.log(`[Network error]: ${networkError}`);
        });

        this._httpLink = new HttpLink({
            uri: this._graphqlServerUrl,
            credentials: this._credentials,
        });
        const links = [errorLink, this._httpLink];
        const apolloClient: ApolloClient<NormalizedCacheObject> = new ApolloClient(
            {
                link: ApolloLink.from(links),
                cache: new InMemoryCache({
                    ...this._cacheInMemoryRules,
                    addTypename: false,
                }),
                fragmentMatcher: this._fragmentMatcher,
            }
        );
        return apolloClient;
    }
}

export { EApolloCLientCredentials, ClsApolloClient };
Stowage answered 28/9, 2020 at 7:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.