Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[@types/koa-router] incompatible type with koa #36161

Closed
4 tasks done
lili21 opened this issue Jun 13, 2019 · 25 comments
Closed
4 tasks done

[@types/koa-router] incompatible type with koa #36161

lili21 opened this issue Jun 13, 2019 · 25 comments

Comments

@lili21
Copy link

lili21 commented Jun 13, 2019

If you know how to fix the issue, make a pull request instead.

Source Code

import Router from 'koa-router'
import { Context } from 'koa'

const router = new Router()

router.get(
  '/auth',
  async (ctx: Context): Promise<void> => {
    ctx.body = 'aaa'
  }
)

Error Message

Argument of type '(ctx: Context) => Promise<void>' is not assignable to parameter of type 'Middleware<ParameterizedContext<any, IRouterParamContext<any, {}>>>'.
  Types of parameters 'ctx' and 'context' are incompatible.
    Property 'log' is missing in type 'BaseContext & { app: import("/Users/li.li/Work/poking/node_modules/@types/koa/index.d.ts")<any, {}>; request: Request; response: Response; req: IncomingMessage; res: ServerResponse; ... 4 more ...; respond?: boolean | undefined; } & IRouterParamContext<...>' but required in type 'Context'.ts(2345)
@lili21
Copy link
Author

lili21 commented Jun 13, 2019

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "strict": true,
    "strictPropertyInitialization": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "outDir": "dist",
    "sourceMap": true
  },
  "include": [
    "src"
  ]
}

@ejose19
Copy link
Contributor

ejose19 commented Sep 4, 2019

I also get this error, however you can use BaseContext instead and things will work, I don't know yet if this is expected, but it's not clear which Interface should be used in both koa and koa router contexts.

@KennethSundqvist
Copy link

The error says it's expecting ParameterizedContext, which works when I use it.

In the Koa definition file I found this line interface Context extends ParameterizedContext {}, so that's as close as you can get to using Context itself.

@ejose19, BaseContext is missing some stuff. Search for interface Context extends in the Koa definition file and read backwards from there and you'll see that Context extends more than just BaseContext.

(I'm completely new to TypeScript so I don't really know this stuff, just reading the errors and source code and trying to make sense of things.)

@ejose19
Copy link
Contributor

ejose19 commented Sep 6, 2019

Yes, Parametrized context has way more stuff than BaseContext, however it's still missing some important things like login / logIn / logout / logOut (which they are in Context alone) but if you try to use ctx: Context inside a koa-router route it says it's incompatible. Hope Anyone fix this because we should be using the correct interface.

@ejose19
Copy link
Contributor

ejose19 commented Sep 6, 2019

I digged a bit more and saw that libraries like koa-session / koa-generic-session / koa-passport (and probably many more) are creating / extending their own interface Context (here's an extract from @types/koa-passport)

declare module "koa" {
    interface Context {
        login(user: any, options?: any): Promise<void>;
        logIn: Context["login"];

        logout(): void;
        logOut: Context["logout"];

        isAuthenticated(): boolean;
        isUnauthenticated(): boolean;
    }
}

That's why ParametrizedContext type is missing all those libraries types, my knowledge in typescript is not enough to solve this issue, but I hope this information leads to the proper resolution.

@calisven
Copy link

For anyone still stuck on this issue, simply removing the type definition on the ctx parameter fixes the problem:

baseRouter.get( '/auth', async (ctx): Promise<void> => { ctx.body = 'aaa' } )

@mattbishop
Copy link
Contributor

If I use require I don't have an issue using a new Koa() koa-websocket: const Koa = require("Koa")

@mattbishop
Copy link
Contributor

I found another way to fix this issue--blow away node_modules and your lock file (if any) and re-install everything.

The problem is all the @types koa additives like koa-router, koa-compose and kao-websockets all include a dependency on "@types/koa": "*". NPM/Yarn downloads these at the current version and stores them local to the Koa-router types module.

When one updates the koa types to a new version, the old downloads for additive packages are not updated too. Deleting the node_modules and lock files causes npm or yarn to redownload everything to the same version of @types/koa.

@mingchen
Copy link
Contributor

mingchen commented Nov 7, 2019

Remove node_modules and package-lock.json then reinstall with npm install do NOT solve the problem.

The following code can be used to reproduce this issue with `koa-session':

// npm install koa koa-session koa-router
// npm install -D @types/koa @types/koa-session @types/koa-router
import Koa from 'koa';
import session from 'koa-session';
import Router from 'koa-router';

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

app.keys = ['key1', 'key2'];

const CONFIG = {
  key: 'koa:sess',
  maxAge: 86400000
};

app.use(session(CONFIG, app));

router.get('/', (ctx) => {
  ctx.body = 'welcome';
  ctx.session.name = 'abc';
});

app.use(router.routes())
   .use(router.allowedMethods());

app.listen(3000);

When run this code with ts-node, it will generate following error:

koarouterissue.ts(21,7): error TS2339: Property 'session' does not exist on type 'ParameterizedContext<any, IRouterParamContext<any, {}>>'.

@evenfrost
Copy link
Contributor

evenfrost commented Nov 16, 2019

Same with koa-passport.

Property 'login' does not exist on type 'ParameterizedContext<any, IRouterParamContext<any, {}>>'.

@bsramin
Copy link

bsramin commented Nov 19, 2019

same issue here

@emilioSp
Copy link

Any news? I've the same problem.

@bsramin
Copy link

bsramin commented Nov 19, 2019

the problem seems to be 2.0.52.

if forced to 2.0.50

  "resolutions": {
    "@types/koa": "2.0.50"
  },

and I also force to 2.0.50 in dependencies

"@types/koa": "2.0.50",

it works again!

@luckyoneday
Copy link

same problem.and use "@types/koa": "2.0.50" can fix this problem, but cannot use koa.Next to type next() function.

@roblevintennis
Copy link

Yes, we're having this same exact issue and have also force locked to 2.0.50 until this gets fixed.

@hengkx
Copy link
Contributor

hengkx commented Nov 27, 2019

How to solve?

@roblevintennis
Copy link

@hengkx if you first remove it, then do:; yarn add @types/koa@2.0.50 it'll for time being lock it. My thought is when I see this has been fixed I'll add back the ^ in package.json.

@youshoubianer
Copy link

@lili21
koa-router call the handler function with RouterContext type , but the handler function we defined need the Context type. Context type maybe defined some other properties which are not in RouterContext, so the type checking can not success.

we can resolve this with Intersection Types.

import { RouterContext } from "koa-router";
router.get(
  '/auth',
  async (ctx: Context & RouterContext): Promise<void> => {
    ctx.body = 'aaa'
  }
)

@zfeed
Copy link

zfeed commented Jan 6, 2020

koa provides us with multiple types for ctx. At this moment we only need to care about Context and ParameterizedContext
Some libraries extends Context by typescript declaration merging. For example, koa-sessiondoes it

declare module "koa" {
    interface Context {
        session: session.Session | null;
        readonly sessionOptions: session.opts | undefined;
    }
}

Fortunately or unfortunately koa-router uses ParameterizedContext instead of Context for typing ctx object in middlewares (actually it's provided by koa, but it doesn't matter here). That is why the code bellow shows an error

import Router from 'koa-router';
import { Context } from 'koa';

const router = new Router();

router.post('/', (ctx: Context) => { // error: Argument of type '(ctx: Context) => void' is not assignable to parameter of type 'Middleware<ParameterizedContext<any, IRouterParamContext<any, {}>>>' because it is missing the following properties from type 'Context': session, sessionOptions
    ctx.body = 'Hello worls';
});

To fix this problem we just need to use capabilities of generic Router class

import Router from 'koa-router';
import { DefaultState, Context } from 'koa';

const router = new Router<DefaultState, Context>();

router.post('/', (ctx: Context) => {
    ctx.body = 'Hello world';
});

Some people recommend to use BaseContext (or DefaultContext in new versions). I recommend to avoid it, because it simply has [key: string]: any; that allows to put whatever you want. Typescript was actually developed for avoiding such things

You may not have such an issue if you use @types/koa@2.0.50. But it's because the same [key: string]: any; which was moved to DefaultContext in new versions

@ejose19
Copy link
Contributor

ejose19 commented Jan 6, 2020

@zfeed Your solution worked extremely well, now all library methods (session, passport) are accessible inside ctx router middleware, also just declaring the interface once per router instead of on each route handles this issue very elegantly. Cheers!

@ejose19
Copy link
Contributor

ejose19 commented Jan 27, 2020

A note for users defining their route callback outside the route (like this)

function getUser(ctx: Context){...}

router.post('/user/:id', getUser)

In that case typescript won't know about the declaration merging and Context won't contain router specific properties (like ctx.params)

One solution is to use a custom defined "RouterContext" that applies the type mentioned by @zfeed :

export type RContext = ParameterizedContext<
  DefaultState,
  Context & Router.IRouterParamContext<DefaultState, Context>
>;

function getUser(ctx: RContext) {
  ctx.params; // <--- this will be found
}

And now both router properties and koa will be available as RContext

@kristof-mattei
Copy link
Contributor

@ejose19 Thank you very much.

@ehsankhf
Copy link

Thanks @zfeed

@damianobarbati
Copy link

Typescript sucks.

@orta
Copy link
Collaborator

orta commented Jun 7, 2021

Hi thread, we're moving DefinitelyTyped to use GitHub Discussions for conversations the @types modules in DefinitelyTyped.

To help with the transition, we're closing all issues which haven't had activity in the last 6 months, which includes this issue. If you think closing this issue is a mistake, please pop into the TypeScript Community Discord and mention the issue in the definitely-typed channel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests