Skip to content

Conversation

@RobinTail
Copy link
Contributor

@RobinTail RobinTail commented Sep 14, 2024

Alternative to #69846 (comment) — the author is sick and can not continue.

The primary goal of this PR is to release the types for express version 5 — the main difference is allowing Promise<void> along with void on RequestHandler.

Challenge: void was technically compatible with anything actually returned, but void | Promise<void> is not.

Tracked in: expressjs/express#5944


Please fill in this template.

Select one of these and delete the others:

If adding a new definition:

  • The package does not already provide its own types, or cannot have its .d.ts files generated via --declaration
  • If this is for an npm package, match the name. If not, do not conflict with the name of an npm package.
  • Create it with dts-gen --dt, not by basing it on an existing project.
  • Represents shape of module/library correctly
  • tsconfig.json should have noImplicitAny, noImplicitThis, strictNullChecks, and strictFunctionTypes set to true.

If changing an existing definition:

If removing a declaration:

  • If a package was never on Definitely Typed, you don't need to do anything. (If you wrote a package and provided types, you don't need to register it with us.)
  • Delete the package's directory.
  • Add it to notNeededPackages.json.

@RobinTail
Copy link
Contributor Author

RobinTail commented Sep 14, 2024

✅ All tests pass now.

  • some packages have mistakes is tests
  • some packages have wrong types
  • some packages have discrepancies in the declared dependencies
  • some declare express compatibility as * which is probably not true, and really implies ^4, but...

I'm requesting comments and I'm open for advises and suggestions on how this important change could be made even better and released faster.

@RobinTail RobinTail marked this pull request as ready for review September 14, 2024 11:14
@typescript-bot
Copy link
Contributor

typescript-bot commented Sep 14, 2024

@RobinTail Thank you for submitting this PR!

This is a live comment that I will keep updated.

This PR touches some part of DefinitelyTyped infrastructure, so a DT maintainer will need to review it. This is rare — did you mean to do this?

16 packages in this PR (and infra files)

Code Reviews

Because this is a widely-used package, a DT maintainer will need to review it before it can be merged.

You can test the changes of this PR in the Playground.

Status

  • ✅ No merge conflicts
  • ✅ Continuous integration tests have passed
  • ✅ A DT maintainer needs to approve changes that affect DT infrastructure (attw.json)

All of the items on the list are green. To merge, you need to post a comment including the string "Ready to merge" to bring in your changes.


Diagnostic Information: What the bot saw about this PR
{
  "type": "info",
  "now": "-",
  "pr_number": 70563,
  "author": "RobinTail",
  "headCommitOid": "8f3a52d98bbbe1539d19bda7cc63581c241d4d9b",
  "mergeBaseOid": "b0208c9d870b7bfa747d7ed9c7c108c95207cc97",
  "lastPushDate": "2024-09-14T08:37:10.000Z",
  "lastActivityDate": "2024-09-25T19:08:01.000Z",
  "mergeOfferDate": "2024-09-25T17:37:04.000Z",
  "mergeRequestDate": "2024-09-25T19:08:01.000Z",
  "mergeRequestUser": "RobinTail",
  "hasMergeConflict": false,
  "isFirstContribution": false,
  "tooManyFiles": false,
  "hugeChange": false,
  "popularityLevel": "Critical",
  "pkgInfo": [
    {
      "name": null,
      "kind": "edit",
      "files": [
        {
          "path": "attw.json",
          "kind": "infrastructure"
        }
      ],
      "owners": [],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Critical",
      "isSafeInfrastructureEdit": false
    },
    {
      "name": "absolute-url",
      "kind": "edit",
      "files": [
        {
          "path": "types/absolute-url/package.json",
          "kind": "package-meta-ok"
        }
      ],
      "owners": [
        "tpluscode",
        "ludovicm67"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "architect__functions",
      "kind": "edit",
      "files": [
        {
          "path": "types/architect__functions/test/http-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "activescott",
        "ryanblock",
        "reconbot"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "create-test-server",
      "kind": "edit",
      "files": [
        {
          "path": "types/create-test-server/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "midgleyc"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "express-brute",
      "kind": "edit",
      "files": [
        {
          "path": "types/express-brute/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "cyrilschumacher"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "express-oauth-server",
      "kind": "edit",
      "files": [
        {
          "path": "types/express-oauth-server/express-oauth-server-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/express-oauth-server/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "atd-schubert"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "express-serve-static-core",
      "kind": "edit",
      "files": [
        {
          "path": "types/express-serve-static-core/.npmignore",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express-serve-static-core/express-serve-static-core-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/express-serve-static-core/index.d.ts",
          "kind": "definition"
        },
        {
          "path": "types/express-serve-static-core/package.json",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express-serve-static-core/v4/.eslintrc.json",
          "kind": "package-meta",
          "suspect": "edited"
        },
        {
          "path": "types/express-serve-static-core/v4/.npmignore",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express-serve-static-core/v4/express-serve-static-core-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/express-serve-static-core/v4/index.d.ts",
          "kind": "definition"
        },
        {
          "path": "types/express-serve-static-core/v4/package.json",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express-serve-static-core/v4/tsconfig.json",
          "kind": "package-meta-ok"
        }
      ],
      "owners": [
        "borisyankov",
        "micksatana",
        "JoseLion",
        "dwrss",
        "andoshin11"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Critical"
    },
    {
      "name": "express-ua-middleware",
      "kind": "edit",
      "files": [
        {
          "path": "types/express-ua-middleware/index.d.ts",
          "kind": "definition"
        }
      ],
      "owners": [
        "peterblazejewicz"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "express",
      "kind": "edit",
      "files": [
        {
          "path": "types/express/.npmignore",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express/express-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/express/package.json",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express/v4/.eslintrc.json",
          "kind": "package-meta",
          "suspect": "edited"
        },
        {
          "path": "types/express/v4/.npmignore",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express/v4/express-tests.ts",
          "kind": "test"
        },
        {
          "path": "types/express/v4/index.d.ts",
          "kind": "definition"
        },
        {
          "path": "types/express/v4/package.json",
          "kind": "package-meta-ok"
        },
        {
          "path": "types/express/v4/tsconfig.json",
          "kind": "package-meta-ok"
        }
      ],
      "owners": [
        "borisyankov",
        "CMUH",
        "puneetar",
        "dfrankland"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Critical"
    },
    {
      "name": "feathersjs__express",
      "kind": "edit",
      "files": [
        {
          "path": "types/feathersjs__express/feathersjs__express-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "j2L4e",
        "DadUndead"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "forest-express-mongoose",
      "kind": "edit",
      "files": [
        {
          "path": "types/forest-express-mongoose/forest-express-mongoose-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "SteveBunlon",
        "ghusse"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "forest-express-sequelize",
      "kind": "edit",
      "files": [
        {
          "path": "types/forest-express-sequelize/forest-express-sequelize-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "SteveBunlon",
        "ghusse"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "fusebit__oauth-connector",
      "kind": "edit",
      "files": [
        {
          "path": "types/fusebit__oauth-connector/fusebit__oauth-connector-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "andrewrmiller",
        "hashiphoto",
        "andydam"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "logfmt",
      "kind": "edit",
      "files": [
        {
          "path": "types/logfmt/logfmt-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "ebroder"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "mock-req-res",
      "kind": "edit",
      "files": [
        {
          "path": "types/mock-req-res/mock-req-res-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "sandorTuranszky"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "mongoose-aggregate-paginate-v2",
      "kind": "edit",
      "files": [
        {
          "path": "types/mongoose-aggregate-paginate-v2/mongoose-aggregate-paginate-v2-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "acrilex1"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    },
    {
      "name": "swaggerize-express",
      "kind": "edit",
      "files": [
        {
          "path": "types/swaggerize-express/swaggerize-express-tests.ts",
          "kind": "test"
        }
      ],
      "owners": [
        "mugeso",
        "nickmorton"
      ],
      "addedOwners": [],
      "deletedOwners": [],
      "popularityLevel": "Well-liked by everyone"
    }
  ],
  "reviews": [
    {
      "type": "approved",
      "reviewer": "jakebailey",
      "date": "2024-09-25T17:36:23.000Z",
      "isMaintainer": true
    },
    {
      "type": "stale",
      "reviewer": "ludovicm67",
      "date": "2024-09-23T11:46:42.000Z",
      "abbrOid": "635727b"
    },
    {
      "type": "stale",
      "reviewer": "midgleyc",
      "date": "2024-09-23T10:44:45.000Z",
      "abbrOid": "635727b"
    },
    {
      "type": "stale",
      "reviewer": "tpluscode",
      "date": "2024-09-16T12:34:58.000Z",
      "abbrOid": "635727b"
    }
  ],
  "mainBotCommentID": 2350955911,
  "ciResult": "pass"
}

@typescript-bot
Copy link
Contributor

@typescript-bot typescript-bot added Maintainer Approved Self Merge This PR can now be self-merged by the PR author or an owner and removed Unreviewed No one showed up to review this PR, so it'll be reviewed by a DT maintainer. labels Sep 25, 2024
@typescript-bot
Copy link
Contributor

@ludovicm67, @midgleyc, @tpluscode Thank you for reviewing this PR! The author has pushed new commits since your last review. Could you take another look and submit a fresh review?

@RobinTail
Copy link
Contributor Author

Ready to merge, @typescript-bot

@typescript-bot typescript-bot merged commit 8093416 into DefinitelyTyped:master Sep 25, 2024
@RobinTail
Copy link
Contributor Author

@jakebailey , thank you for your help and suggestions!

@RobinTail
Copy link
Contributor Author

@jakebailey , sorry, could you please restart the CI in master:
https://github.com/DefinitelyTyped/DefinitelyTyped/actions/runs/11039533650/job/30665324639

Something happended there, looks like a network issue.

@jakebailey
Copy link
Member

@jakebailey
Copy link
Member

But, it will prevent publishing until fixed: https://github.com/microsoft/DefinitelyTyped-tools/actions/workflows/publish-packages.yml

@AviVahl
Copy link
Contributor

AviVahl commented Sep 26, 2024

I wonder, the following now fails linting:

import { createServer } from 'node:http';
import express from 'express';

const app = express();
const httpServer = createServer(app);

with: Promise returned in function argument where a void return was expected. eslint@typescript-eslint/no-misused-promises

when using type-checked typescript-eslint configuration.

This is because app is typed as core.Express which extends Application which extends IRouter which extends RequestHandler, which now returns both void and Promise<void>.

If this is a valid case (Application being a valid node http request handler), perhaps make it so it's typed as returning void, while still accepting async request handlers in .use(...)? I mean, if express handles promise rejections on its own... void alone might be fine. WDYT?

@RobinTail
Copy link
Contributor Author

RobinTail commented Sep 26, 2024

eslint@typescript-eslint/no-misused-promises

I'm not getting such warning, maybe because that rule is not included into recommended configuration.

Nevertheless, the rule has a lot of options and you can tune it according to your situation, @AviVahl , or disable for a particular statement.
https://typescript-eslint.io/rules/no-misused-promises/

If you believe the type declaration should be corrected, feel free to create another PR for making corresponding adjustments and the further releasing @types/[email protected].

@AviVahl
Copy link
Contributor

AviVahl commented Sep 26, 2024

the rule is only included in configs.recommendedTypeChecked, which also requires one to specify additional settings (such as projectService or project, etc.)

I realize I can disable lint for that line/file, cast the type, or disable rule. The thing is... I believe the rule is correct. The express handler possibly returns a Promise (according to the type), and node http handler doesn't handle promises. Just an FYI, since it might be a common use-case to use the app itself as handler for a native http server.

Not sure I want to tackle this on my own. I'll probably just workaround in user-end.

@davps
Copy link

davps commented Oct 23, 2024

There seems to be a version management discrepancy. While @types/express has already moved to v5 (via #70563), npm outdated still considers Express 4.21.1 as the "latest" version:

Current package.json:

{
  "dependencies": {
    "express": "^5.0.1"
  },
  "devDependencies": {
    "@types/express": "^5.0.0"
  }
}

Running npm outdated shows:

Package   Current  Wanted  Latest   Location              Depended by
express   5.0.1    5.0.1   4.21.1  node_modules/express  [project-name]

This creates potential confusion since:

  1. The types have officially moved to v5
  2. Users running npm outdated might think they need to downgrade to 4.21.1. This is my case, I ran into this in my CI/CD.

@jakebailey
Copy link
Member

That was an intentional choice made by the express maintainers; v5 is not marked as latest over there.

DefinitelyTyped has no mechanism to model this somewhat unusual situation.

@davps
Copy link

davps commented Oct 23, 2024

I see, thanks for the clarification @jakebailey

I'll just disable npm outdated for now in my CI/CD since this mismatch happens in both directions - whether using Express v4 with types v4, or Express v5 with types v5, npm outdated always shows version conflicts. I'm sure it will sort itself out as v5 adoption grows. Thanks.

alino20 pushed a commit to alino20/DefinitelyTyped that referenced this pull request Dec 31, 2024
@binarykitchen
Copy link

Not sure I want to tackle this on my own. I'll probably just workaround in user-end.

@AviVahl Have you figured out a workaround yet?

(Experiencing the same issue here)

@AviVahl
Copy link
Contributor

AviVahl commented Feb 23, 2025

Not sure I want to tackle this on my own. I'll probably just workaround in user-end.

@AviVahl Have you figured out a workaround yet?

(Experiencing the same issue here)

use a cast:

import { createServer, type RequestListener } from "node:http";
import express from "express";

const app = express();
const httpServer = createServer(app as RequestListener);

or use @types/[email protected] (latest 4.x types; npm info @types/express versions), if you're still using express@4.

@binarykitchen
Copy link

Thanks, @AviVahl, I'll do this for now, temporarily. Using express@5 here.

Although, force casting should be avoided. Wondering if this has every been raised upstream before and will ever be fixed?

@glasser
Copy link
Contributor

glasser commented May 8, 2025

I ran into the same issue with ESLint configs.recommendedTypeChecked and createServer(app) as @AviVahl. I'll try the as RequestListener workaround, but it is an interesting point that if the app can return a Promise and http.createServer doesn't handle that, it could be a problem? The official Express docs do still teach http.createServer(app) as a reasonable thing to do.

Copy link

@robertomiramon50-stack robertomiramon50-stack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Check Config Changes a module config files Critical package Edits Infrastructure Edits multiple packages Maintainer Approved Self Merge This PR can now be self-merged by the PR author or an owner

Projects

None yet

Development

Successfully merging this pull request may close these issues.