user10706046
user10706046

Reputation:

Koa + TypeScript: Property 'body' does not exist on type Request

I wanted to use koa & koa-bodyparser with TypeScript but whenever I access ctx.request.body I get an error that body doesn't exist on type Request

import Koa from 'koa'
import Router from 'koa-router'
import bodyparser from 'koa-bodyparser'

const app = new Koa()
const router = new Router()

const data = ['lorem', 'ipsum', 'dolor', 'sit', 'amet']

app.use(bodyparser())
router.post('/', (ctx, next) => {
  const phrase = ctx.request.body; // Property 'body' does not exist on type Request
  if (typeof phrase === 'string') {
    ctx.response.body = data.filter(element => element.includes(phrase))
  }
})

Upvotes: 18

Views: 10548

Answers (3)

Bids
Bids

Reputation: 2449

The best way to fix this is using yarn deduplicate as described above, for instance:

yarn 2.x:

yarn dedupe @types/koa

yarn 1.x:

npx yarn-deduplicate --packages @types/koa

Alternatively if you need finer-grained control you can pin @types/koa using a resolution, e.g.:

  "resolutions": {
    "@types/koa": "2.11.3"
  }

This leads to the same behaviour in yarn.lock:

"@types/koa@*", "@types/[email protected]":
  version "2.11.3"

Upvotes: -1

Dan Crews
Dan Crews

Reputation: 3617

If you're here from the future, there's an additional problem that can cause this. Scenario:

  1. Past you: Install koa, koa-bodyparser, @types/koa, @types/koa-bodyparser
  2. Code: Everything works great
  3. Today you: Time for an upgrade; update [all of those packages]
  4. Code: Property 'body' does not exist on type Request

TL;DR: yarn.lock, so run yarn dedupe @types/koa.


What's happened?

Digging deeper, in your node_modules, you see:

- node_modules/
  - @types/koa/
  - @types/koa-bodyparser/
      - node_modules/
      -   @types/koa/

Why does that matter?

Let's take a look at @koa-bodyparser to find out. Here are the relevant lines, and how it works:

import * as Koa from "koa";

declare module "koa" {
    interface Request {
        body?: any;
        rawBody: string;
    }
}

What it does is define extra parameters for the Request type on the koa package that you're using, right? Well, normally, but not quite. It also has a dependency on @types/koa because of the import at the top. What it actually does is define extra parameters for the Request type on the koa object that IT uses, and since it's now using a different version than you are, you don't have that benefit anymore.

OK why did this happen, then?

When you first installed everything, yarn built a dependency tree, looked at the versions in each package.json and ended up with this:

"@types/koa@*", "@types/koa@^2.13.1":
  version "2.13.1"
  ... resolved, integrity, dependencies, etc.

The @types/koa@^2.13.1 will be whatever version you installed in your package.json. The @types/koa@* is what's in @types/koa-bodyparser.

And then when you updated, yarn built a dependency tree, looked at the versions in each package.json and compared that to what it already had. Your code now says @types/koa@^2.13.5, so yarn needs to install a new version for it. @types/bodyparser still says @types/koa@*, which is already accounted for in the yarn.lock, and so you end up with a yarn.lock that looks like this:

"@types/koa@*":
  version "2.13.1"
  ... resolved, integrity, dependencies, etc.

"@types/koa@^2.13.5":
  version "2.13.5"
  ... resolved, integrity, dependencies, etc.

And now that you're not using the same version, one gets installed in your node_modules, and the other gets installed in the node_modules of the package that requested it.

So how do I fix it?

Updated for 2024

You just need to dedupe that one package. Run this to tell yarn to update everything within non-breaking ranges (same result as "previous answer", without manually modifying the lock file).

yarn dedupe @types/koa

If you want to see what other issues you might be facing in the future, you can run this to check (dry run) for ALL packages. Remember: having unnecessary copies means longer install times for developers and longer deployment times.

yarn dedupe --check

Then, if you like it, you can either run

  1. yarn dedupe
    • According to the docs, this will make sure you have the fewest number of copies of a package as possible when versions overlap, which may downgrade some if one library requires a lower version.
    • Because it has to look for version overlap first, it's a little slower, but results in fewer files in the end.
  2. yarn dedupe --strategy highest
    • According to the docs, this will make sure that packages always use the latest version they support, as if you were installing it fresh. If one package requires a lower version and others don't, you'll end up with multiple copies, but the code that isn't limited will have the newest it supports.
    • Because it just uses the highest-supported, it's faster (can do it in one pass), but often results in duplicates.
    • For the current question, the nested package wants *. If your code requires a whole major version less than latest, it might not fix the issue. This is rarer, but if you got this far, you probably want to remember that this is possible.

Note 1: Remember that not all packages follow semver, so you still want to be careful about doing this in one fell swoop across all packages without doing a --check and verifying that you're OK with those changes.

Note 2: If you're using Yarn 1, dedupe isn't built in yet, so I'd install yarn-deduplicate and then run yarn-deduplicate --packages @types/koa.

Previous answer

The easiest way? Delete the whole block of @types/koa@*from your yarn.lock file and run yarn again. You'll now end up with this:

"@types/koa@*", "@types/koa@^2.13.5":
  version "2.13.5"
  ... resolved, integrity, dependencies, etc.

And everything is happy again until next time.

Upvotes: 5

user10706046
user10706046

Reputation:

Run npm install --save-dev @types/koa-bodyparser in a terminal while in the directory where your package.json is

This package contains types introduced by koa-bodyparser (such as request.body)

Upvotes: 25

Related Questions