apollo-client: Type 'ApolloLink' is not assignable to type 'ApolloLink'

Intended outcome: This TypeScript error occurs with a link chain using additive composition and @apollo/client. The goal is to create an Apollo Link composed of an Error Link, a Context Link and an HttpLink or HttpBatchLink.

import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from '@apollo/client';
import { BatchHttpLink } from '@apollo/link-batch-http';
import { onError } from '@apollo/link-error';
import AuthLink from './authLink'

let httpLink: HttpLink | BatchHttpLink;
if (enableBatching === true) {
  httpLink = new BatchHttpLink({
    ...authenticatedHttpSettings,
    batchMax: 30,
  });
} else {
  httpLink = new HttpLink(authenticatedHttpSettings);
}

const errorLink = onError(({ graphQLErrors, operation }) => {
  if (graphQLErrors) {...}
});

const link = from([errorLink, AuthLink(), httpLink]);

  const testApi = new ApolloClient({
    connectToDevTools: true,
    link,
    cache: new InMemoryCache(),
  })

Actual outcome: TypeScript throws an error: Type ‘ApolloLink’ is not assignable to type ‘ApolloLink | RequestHandler’.

How to reproduce the issue: I assume the issue is related to different type definitions for Apollo Link. This should be reproducible with the given code in a Typescript / React environment.

How to solve this issue Currently @apollo/link-http-batch v.2.0.0-beta.3 is using @apollo/client v.3.0.0-beta.23. Downgrading my @apollo/client to 3.0.0-beta.23 worked, but to solve this issue the @apollo/client version should be upgraded in all link packages.

Versions

"react": "^16.12.0",
"react-dom": "^16.12.0",
 "typescript": "^3.7.3",
"@apollo/client": "^3.0.0-beta.38",
"@apollo/link-batch-http": "^2.0.0-beta.3",
"@apollo/link-context": "^2.0.0-beta.3",
"@apollo/link-error": "^2.0.0-beta.3",
"apollo": "^2.24.0",

Full Stack Trace

Type 'import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink' is not assignable to type 'import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink'.
  Types of property 'split' are incompatible.
    Type '(test: (op: import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/types").Operation) => boolean, left: import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/...' is not assignable to type '(test: (op: import("/path/node_modules/@apollo/client/link/core/types").Operation) => boolean, left: import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path...'.
      Types of parameters 'left' and 'left' are incompatible.
        Type 'import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path/node_modules/@apollo/client/link/core/types").RequestHandler' is not assignable to type 'import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/types").Reque...'.
          Type 'ApolloLink' is not assignable to type 'ApolloLink | RequestHandler'.
            Type 'import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink' is not assignable to type 'import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink'.
              Types of property 'split' are incompatible.
                Type '(test: (op: import("/path/node_modules/@apollo/client/link/core/types").Operation) => boolean, left: import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path...' is not assignable to type '(test: (op: import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/types").Operation) => boolean, left: import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/...'.
                  Types of parameters 'left' and 'left' are incompatible.
                    Type 'import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path/node_modules/@apollo/link-batch-http/node_modules/@apollo/client/link/core/types").Reque...' is not assignable to type 'import("/path/node_modules/@apollo/client/link/core/ApolloLink").ApolloLink | import("/path/node_modules/@apollo/client/link/core/types").RequestHandler'.
                      Type 'ApolloLink' is not assignable to type 'ApolloLink | RequestHandler'.```

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 26
  • Comments: 39 (3 by maintainers)

Commits related to this issue

Most upvoted comments

The solution for me was to use the links included in @apollo/client instead of the @apollo/link-* packages. See the part about links in the migration docs for more information:

https://www.apollographql.com/docs/react/migrating/apollo-client-3-migration/#apollo-link-

@dep-dt You should import like this and that is what @afroald mentioned above.

import { onError } from "@apollo/client/link/error";
import { setContext } from "@apollo/client/link/context";

Remove those packages @apollo/link-context and @apollo/link-error as those are already included in the @apollo/client

I still have this issue with @apollo/client:3.0.2

I still have this error, so I used this approach:

link: from([(errorLink as unknown) as ApolloLink, httpLink]),

I still have this issue with @apollo/client:3.1.0

I am using @apollo/client”: “^3.1.3” and still have same issue. Any update ?

According to this article I see

“Apollo Client should use your WebSocketLink for subscriptions, but it shouldn’t use it for queries or mutations. For those operations, Apollo Client should use HTTP as usual. To support this, the @apollo/client library provides a split function that lets you use one of two different Links, according to the result of a boolean check.”

So maybe you need to do something like this?

import { split, HttpLink } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { WebSocketLink } from '@apollo/client/link/ws';

const wsLink = new WebSocketLink({
  uri: `ws://localhost:3000/graphql`,
  options: {
    reconnect: true,
  },
});

const httpLink = new HttpLink({
  uri: 'http://localhost:3000/graphql',
});

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('accessToken');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  };
});

// The split function takes three parameters:
//
// * A function that's called for each operation to execute
// * The Link to use for an operation if the function returns a "truthy" value
// * The Link to use for an operation if the function returns a "falsy" value
const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink,
);

const client = new ApolloClient({
  link: ApolloLink.from([splitLink, authLink]),
  cache: new InMemoryCache(),
});

Apologies in advance, I’ve not worked with WebSocketLink much.

@dep-dt Dude thank you very much for taking the time to help me find the solution, and I worked when I switched

 const client = new ApolloClient({
   link: ApolloLink.from([splitLink, authLink]),
   cache: new InMemoryCache(),
 });

to

const client = new ApolloClient({
  link: ApolloLink.from([authLink, splitLink]),
  cache: new InMemoryCache(),
});

thanks again!

According to this article I see

“Apollo Client should use your WebSocketLink for subscriptions, but it shouldn’t use it for queries or mutations. For those operations, Apollo Client should use HTTP as usual. To support this, the @apollo/client library provides a split function that lets you use one of two different Links, according to the result of a boolean check.”

So maybe you need to do something like this?

import { split, HttpLink } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import { WebSocketLink } from '@apollo/client/link/ws';

const wsLink = new WebSocketLink({
  uri: `ws://localhost:3000/graphql`,
  options: {
    reconnect: true,
  },
});

const httpLink = new HttpLink({
  uri: 'http://localhost:3000/graphql',
});

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('accessToken');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  };
});

// The split function takes three parameters:
//
// * A function that's called for each operation to execute
// * The Link to use for an operation if the function returns a "truthy" value
// * The Link to use for an operation if the function returns a "falsy" value
const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink,
);

const client = new ApolloClient({
  link: ApolloLink.from([splitLink, authLink]),
  cache: new InMemoryCache(),
});

Apologies in advance, I’ve not worked with WebSocketLink much.

@khanakia This worked thanks. Also thanks @afroald 😃

They opened a can of worm on maintaining cross dependency of a common core package, when it really should be as simple as a peer dependency. What a shame.

@afroald It seems working now 💯

@benyou1969 great news!

import Cookie from 'js-cookie';
import config from 'config';
import {
    ApolloClient,
    createHttpLink,
    InMemoryCache,
    ApolloLink,
} from '@apollo/client';
import { WebSocketLink } from '@apollo/link-ws';
import { setContext } from 'apollo-link-context';
import { onError } from '@apollo/link-error';

const wsLink = new WebSocketLink({
    uri: config.server.graphQLWs,
    options: {
        reconnect: true,
    },
});

const httpLink = createHttpLink({
    uri: config.server.graphQLApi,
});

const cache = new InMemoryCache({
    addTypename: false,
});

const errorLink: any = 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}`);
    }
});

const authLink: any = setContext((_, { headers, ...context }) => {
    // get the authentication token from local storage if it exists
    const token = Cookie.get('userToken');
    // return the headers to the context so httpLink can read them
    return {
        headers: {
            ...headers,
            authorization: token ? `Bearer ${token}` : '',
        },
        ...context,
    };
});

const hasSubscriptionOperation = ({ query: { definitions } }) =>
    definitions.some(
        ({ kind, operation }) =>
            kind === 'OperationDefinition' && operation === 'subscription'
    );

export const client = new ApolloClient({
    version: '1',
    resolvers: {},
    cache: cache,
    link: ApolloLink.from([
        errorLink,
        authLink,
        ApolloLink.split(hasSubscriptionOperation, wsLink, httpLink),
    ]),
    queryDeduplication: false,
});

that’s my fix

This issue seems to be resolved in beta.43, but present from beta.44 onward.

My issue was with the ApolloProvider. After upgrading to. @apollo/client 3.1.3 i was still importing ApolloProvider from @apollo/react-hooks. Simply imported it from @apollo/client instead and everything works fine.

@GiselaMD Not sure if I’ve been missing something, tried beta.49 and beta.50 and they both gave me type errors on all @apollo/link-error, @apollo/link-context and @apollo/link-retry.

  "devDependencies": {
    "@apollo/client": "3.0.0-beta.49",
    "@apollo/link-context": "^2.0.0-beta.3",
    "@apollo/link-error": "^2.0.0-beta.3",
    "@apollo/link-retry": "^2.0.0-beta.3",

@vicary to get around the blocker temporarily, @wamujlb’s solution is certainly viable. It is just a types issue so shouldn’t affect anything during runtime.