Apollo-client: Typescript error when compiling a module using apollo-client and apollo-cache-inmemory

Created on 7 Nov 2017  ·  21Comments  ·  Source: apollographql/apollo-client

Intended outcome:

Successful compilation of the project.

Actual outcome:

ERROR in [at-loader] ./node_modules/apollo-cache-inmemory/lib/inMemoryCache.d.ts:5:22
    TS2415: Class 'InMemoryCache' incorrectly extends base class 'ApolloCache<NormalizedCacheObject>'.
  Types of property 'read' are incompatible.
    Type '<T>(query: ReadOptions) => T | null' is not assignable to type '<T>(query: ReadOptions) => T'.
      Type 'T | null' is not assignable to type 'T'.
        Type 'null' is not assignable to type 'T'.

How to reproduce the issue:
tsconfig.json

{
  "compilerOptions": {
    "sourceMap": true,
    "jsx": "preserve",
    "target": "es2015",
    "lib": ["es2017", "dom", "esnext.asynciterable"],
    "module": "es2015",
    "moduleResolution": "node",
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": false,
    "baseUrl": ".",
    "paths": {
    }
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

Sample module:

import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient, ApolloQueryResult } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import gql from "graphql-tag";

const client = new ApolloClient({
  cache: new InMemoryCache() as any,
  link: new HttpLink({ uri: process.env.GRAPHQL_ENDPOINT })
});

Version

* Possible cause *

apollo-cache defines ApolloCache base class with read method which cannot miss:

abstract read<T>(query: Cache.ReadOptions): T

apollo-cache-inmemory actually has more realistic definition of the return value as T | null

⛑ TypeScript 🐞 bug

Most helpful comment

Am I right to assume that this is still not fixed? I have this code:

    const client = new ApolloClient({
      cache: new InMemoryCache(),
      link: batchHttpLink,
      queryDeduplication: true,
      ssrMode: true,
    })

and am getting this TS error:

Type 'InMemoryCache' is not assignable to type 'ApolloCache<NormalizedCacheObject>'.
  Property 'data' is protected in type 'InMemoryCache' but public in type 'ApolloCache<NormalizedCacheObject>'. [2322]

All 21 comments

Temporary, and unfortunate, workaround is to set "strictNullChecks": false 😞

@tackley thank you for the suggestion.

After following the suggestion to set strictNullChecks to false. I experience another TypeError:

'Type 'ApolloClient<NormalizedCacheObject>' is not assignable to type 'ApolloClient<Cache>'

Below is the client/server code for rendering resulting in the error. The ApolloClient is created as stated in the docs.

// server.js
export const rootRoute = (req: express.Request, res: express.Response) => {
  const location = req.url
  const context: AppContext = {}
  const client = createApolloServer() // Create ApolloClient
  const store: Redux.Store<Store> = configureStore()

  const rawHTML = (
    <ApolloProvider client={client}> <----ERROR FROM ABOVE HERE
      <Provider store={store}> <---- Redux store
        <StaticRouter location={location} context={context}>
          <Main />
        </StaticRouter>
      </Provider>
    </ApolloProvider>
  )
}
// client.js
  const client = createApolloBrowser()
  const history = createHistory()
  const store: Redux.Store<Store> = configureStore()

  hydrate(
    <ApolloProvider client={client}> <----ERROR FROM ABOVE HERE
      <Provider store={store}> <---- Redux store
        <ConnectedRouter history={history}>
          <Main />
        </ConnectedRouter>
      </Provider>
    </ApolloProvider>,
    rootNode
  )

Below are the current set of dependencies:

    "apollo-cache-inmemory": "^1.1.0",
    "apollo-client-preset": "^1.0.2",
    "apollo-client": "^2.0.2",
    "apollo-link-context": "^1.0.0",
    "apollo-link-http": "^1.1.0",
    "react-apollo": "^2.0.0"

Thank you team Apollo for all your effort!

For now you can also set skipLibCheck to true. Might be better for this issue.

@donaldpipowitch still seeing the error. Webpack emits

TS2322: Type '{ client: ApolloClient<NormalizedCacheObject>; children: Element; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<ApolloProvider> & Readonly<{ children?: ReactNode;...'.
  Type '{ client: ApolloClient<NormalizedCacheObject>; children: Element; }' is not assignable to type 'Readonly<ProviderProps<Cache>>'.
    Types of property 'client' are incompatible.
      Type 'ApolloClient<NormalizedCacheObject>' is not assignable to type 'ApolloClient<Cache>'.
        Type 'NormalizedCacheObject' is not assignable to type 'Cache'.
          Property 'add' is missing in type 'NormalizedCacheObject'.

Yeah, same error here

The issue seems to be that the Cache type parameter isn't declared anywhere in react-apollo's type definitions

This seems to work together with skipLibCheck: true.

import { ApolloCache } from 'apollo-cache';
import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';

const client = new ApolloClient({
  cache: new InMemoryCache() as ApolloCache<NormalizedCacheObject>,
  link: new HttpLink({ uri: '/graphql' }),
});

// ... later ...

<ApolloProvider client={client as ApolloClient<any>}>
  {/* ... */}
</ApolloProvider>

While the return type of the read method in the base class is still an issue, I think the issue related to ApolloProvider should be resolved by apollographql/react-apollo#1299.

Does anyone have an example TS project I can use to test changes and fix this?

@jbaxleyiii Here's a minimal repository reproducing this bug: https://github.com/AlexanderEkdahl/apollo-client-typescript-bug

@jbaxleyiii I'm afraid this did not fix the issue.

If you clone my repository and then run yarn upgrade followed by ./node_modules/.bin/tsc the issue persists. The fix is to modify the base class to allow null being returned from the read query. The client expects a type conforming to the base class which the InMemoryCache class does not.

@jbaxleyiii please re-open, just installed everything in a new project ([email protected]). I'm still getting this error.

This still happens: https://gist.github.com/prencher/ad626ca0ec21ce8bfc41e4bfcfc54a81

Turning strictNullChecks off is _not_ an answer to this problem. What can we do to get this actually resolved?

@jbaxleyiii It seems like you merged what may be a fix just after the most recent release - assuming that's correct, can we get a patch release, or at least a beta/rc with the fix?

@prencher we'll follow up on this ASAP - thanks for your patience!

Am I right to assume that this is still not fixed? I have this code:

    const client = new ApolloClient({
      cache: new InMemoryCache(),
      link: batchHttpLink,
      queryDeduplication: true,
      ssrMode: true,
    })

and am getting this TS error:

Type 'InMemoryCache' is not assignable to type 'ApolloCache<NormalizedCacheObject>'.
  Property 'data' is protected in type 'InMemoryCache' but public in type 'ApolloCache<NormalizedCacheObject>'. [2322]

@mbrochh
The trick (?) is to use the interface NormalizedCacheObject as the generic type for TCacheShape:

new ApolloClient<NormalizedCacheObject>({
    ssrMode: typeof window === 'undefined',
    link: auth.concat(http),
    cache: new InMemoryCache(),
});

This is still an issue.

"apollo-boost": "^0.4.7",
    "react-apollo": "^3.1.3",

My code

import React from 'react'
import ReactDOM from 'react-dom'
import { withApollo, ApolloProvider } from 'react-apollo'
import { ApolloClient, ApolloLink, InMemoryCache, HttpLink, NormalizedCacheObject } from 'apollo-boost'

const httpLink = new HttpLink({ uri: url })

const authLink = new ApolloLink((operation, forward) => {
  // Call the next link in the middleware chain.
  return forward(operation)
})

const client = new ApolloClient<NormalizedCacheObject>({
  link: authLink.concat(httpLink), // Chain it with the HttpLink
  cache: new InMemoryCache() as any
})

const AppWithApollo = withApollo(App)

const Index = () => (
  <ApolloProvider client={client as ApolloClient<any>}>
    <AppWithApollo />
  </ApolloProvider>
)

ERROR in /Users/Peter/Workspace/petenelson.dev/src/index.tsx
./src/index.tsx
[tsl] ERROR in /Users/Peter/Workspace/petenelson.dev/src/index.tsx(23,46)
TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type '{ client: ApolloClient; }' is not assignable to parameter of type 'Attributes & ApolloProviderProps'.
Property 'children' is missing in type '{ client: ApolloClient; }' but required in type 'ApolloProviderProps'.

For those looking for a great example of next with apollo and typescript, here's the repo that saved me: https://github.com/borisowsky/next-advanced-starter

This compiles in TypeScript for me

import { ApolloClient } from 'apollo-client';
import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';

export function createApolloClient(): ApolloClient<NormalizedCacheObject> {
  return new ApolloClient({
    link: new HttpLink({
      uri: "...",
    }),
    cache: new InMemoryCache(),
  });
}

I fixed it by removing apollo-boost dependency.

Was this page helpful?
0 / 5 - 0 ratings