typescriptexpressgraphqlbackendapollo-server

Apollo GraphQL Server: RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>> is not assignable to Application<Record<string, any>>


I am setting up an Express-Typescript application to create a GraphQL server using ApolloServer. However, I encountered a type error while trying to use expressMiddleware for my GraphQL endpoint. Here's the code:

import "dotenv/config";
import express from 'express';
import cors from 'cors';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServer } from '@apollo/server';

const gqlServer = new ApolloServer({
    typeDefs: `
        type Query {
            hello: String
        }
    `,
    resolvers: {
        Query: {
            hello: () => 'Hello world!',
        }
    },
});

async function init() {
    const app = express();
    const port = Number(process.env.PORT) || 4000;

    app.use(cors());
    app.use(express.json());
    app.use(express.urlencoded({ extended: true }));

    await gqlServer.start();

    app.get('/', (req, res) => {
        res.send('Hello World!');
    });

    app.use("/graphql", expressMiddleware(gqlServer)); // Error Here

    app.listen(port, () => {
         console.log(`Server is running on http://localhost:${port}`);
    });
}

init();

tsconfig.json file has

{
    "compilerOptions": {
        "target": "es2016",
        "module": "CommonJS",
        "rootDir": "./src",
        "outDir": "./dist",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
    }
}

Package.json file has:

{
    "name": "server",
    "version": "1.0.0",
    "main": "index.js",
    "type": "module",
    "scripts": {
        "build": "tsc",
        "start": "node dist/index.js",
        "dev": "tsc-watch --onSuccess \"npm start\"",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "dependencies": {
        "@apollo/server": "^4.11.2",
        "cors": "^2.8.5",
        "dotenv": "^16.4.7",
        "express": "^4.21.2",
        "graphql": "^16.10.0"
    },
    "devDependencies": {
        "@types/cors": "^2.8.17",
        "@types/dotenv": "^8.2.3",
        "@types/express": "^5.0.0",
        "nodemon": "^3.1.9",
        "tsc": "^2.0.4",
        "tsc-watch": "^6.2.1",
        "typescript": "^5.7.2"
    }
}

Error: The TypeScript compiler throws the following error:

Argument of type 'RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' is not assignable to parameter of type 'Application<Record<string, any>>'.


Solution

  • What's wrong?

    Looking at your package.json, you're using Express version 4, but you have the @types/express for Express 5. These won't match up.

           "express": "^4.21.2",
            "@types/express": "^5.0.0",
    

    How to fix it?

    In your devDependencies, change this line:

    "@types/express": "^5.0.0",
    

    to this

    "@types/express": "^4.17.21",
    

    and then reinstall your packages (npm install or yarn install).


    How did this happen?

    Express v5 is in next, so when you do npm install express, you get v4, but DefinitelyTyped (where the @types/* come from) has v5 published as latest, so when you do npm install @types/express, you get v5. That means on fresh projects, you'll have to be specific until either Express5 gets fully released or DefinitelyTyped updates their npm tags.