Using custom scalars with Apollo Client in TypeScript

In http://blog.wafrat.com/querying-dapp-graphql-databases-in-react-and-typescript-hosted-on-the-graph/, I had queried a BigInt and forced apollo client:codegen to pass through custom scalar without renaming it. And it worked because TypeScript luckily already has this type defined. What if it were a scalar type that does not exist in TypeScript like BigDecimal?

Passing through scalars

As a reminder, here's the command I use to generate my types:

apollo client:codegen types --target=typescript --endpoint=https://api.thegraph.com/subgraphs/name/aave/protocol-v2 --passthroughCustomScalars                      

This command will go through all my typescript files, find GraphQL queries, then fetch the corresponding types from the Aave TheGraph subgraph.

The passthroughCustomScalars options makes it so that Aave's BigInt and BigDecimal scalars are parsed as is. The resulting ts file looks like this:

/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.

// ====================================================
// GraphQL query operation: ReserveQuery
// ====================================================

export interface ReserveQuery_reserve {
  __typename: "Reserve";
  /**
   * Reserve address
   */
  id: string;
  isActive: boolean;
  isFrozen: boolean;
  availableLiquidity: BigInt;
  totalLiquidity: BigInt;
  utilizationRate: BigDecimal;
  optimalUtilisationRate: BigInt;
  ...
}
...

The problem is BigDecimal is not a standard TypeScript type, so the compiler complains:

Cannot find name 'BigDecimal'.

I could easily fix it by manually adding an alias to the top of this file, such as type BigDecimal = number;. However, that would force me to add this line everytime I regenerate the file. It's not a good idea, and the comment in the generated file also dissuades us to do that.

The tool also generates a file called globalTypes.ts, but this too is marked as "should not be edited".

In the doc for client:codegen, there are a few more parameters that seem related, like globalTypesFile, or namespace, but ultimately the description explains something else.

Googling for "Apollo custom scalars" got me to the Apollo page on Custom Scalars. But it's for Apollo Server, not Apollo Client. And there's even a note in the page that tells us that Custom Scalars are not supported on Apollo Client.

You can check out the GitHub ticket. It's been open since 2018, and the conversation is way above my head. They mention some custom library for a workaround. For such a simple scalar, I don't want to go for such a heavy solution.

Eventually I found a conversation about what I am trying to do: apollo-tooling: generating-typescript-types-with-custom-scalars. It doesn't say explictly how to define globals though.

A few more searches led me to this post on StackOverflow. So the solution is to create a file called whatever.d.ts, then define the type in it. I tried export type BigDecimal = BigInt; but it did not work. Actually you shouldn't use the export keyword at all. So it should be like this:

type BigDecimal = BigInt;

And suddenly, the project started to compile again.

During my search, I had also stumbled on this GitHub issue, which describes the same solution. If I had found it first, it'd have saved me quite a bit of time.