DefinitelyTyped/types/koa
Anton Astashov b081a5b7d0 [@types/koa]: Parameterize Context and Application. (#31704)
* [@types/koa]: Parameterize `Context` and `Application`.

Currently, `ctx.state` is `any`, and `ctx` itself allows any fields to
be inside `Context`. That's essentially 2 places where developers can
add their custom properties, and would be great to opt-in into more
typesafe approach than it's currently is.

What if we parameterize `Context` and `Application` with 2 types - one
will define `ctx.state`, and another - fields in `Context`? Then, if you
chain `use`, TypeScript will infer the types properly for your
middlewares. Like:

```typescript
interface NewContext {
  orgh: string;
}

interface FooState {
  foo: string;
}

interface BarState {
  bar: string;
}

async function fooMiddleware(
  ctx: Koa.Context<FooState>,
  next: () => Promise<void>
): Promise<void> {
  ctx.state.foo = "foo";
  await next();
}

async function barMiddleware(
  ctx: Koa.Context<BarState>,
  next: () => Promise<void>
): Promise<void> {
  ctx.state.bar = "bar";
  await next();
}

const app = new Koa<{}, {}>()
  .use(fooMiddleware)
  .use(barMiddleware)
  .use<{}, NewContext>(async (ctx, next) => {
    // Here ctx is inferred as Koa.Context<FooState & BarState, NewContext>
    ctx.orgh = "bazinga";
    await next();
  })
  .use(async (ctx, next) => {
    // Here ctx is inferred as Koa.Context<FooState & BarState, NewContext>
    await next();
  });
// `app` here is `Koa<FooState & BarState, NewContext>`

app.listen(3000);
```

So, if you define `const app = new Koa<{}, {}>()`, then you'll opt-in
into "typesafe" Koa Context. But if you do just `const app = new Koa()`,
you still will have `ctx.state: any`, like before. So, it should be
backwards-compatible.

But even in this case you can specify what the `ctx` is inside
the middlewares, like:

```typescript
const app2 = new Koa();
app2.use(fooMiddleware);
app2.use(async (ctx, next) => {
  // `ctx.state` here is inferred as `any`
  ctx.state.prop = "Some Prop";
  await next();
});
app2.use(async (ctx: Koa.Context<{}, NewContext>, next) => {
  ctx.orgh = "oh yeah";
  await next();
});
app2.use(async (ctx: Koa.Context<FooState>, next) => {
  ctx.state.foo = "Yay";
  await next();
});
```

What do you think?

* Rename new `Context` to `ParameterizedContext`

So that all the old hacks with declaration merging of Koa's `Context`
wouldn't break.

* Fix the build

* Use Context instead of ParameterizedContext when possible
2018-12-31 10:35:34 -08:00
..
index.d.ts [@types/koa]: Parameterize Context and Application. (#31704) 2018-12-31 10:35:34 -08:00
koa-tests.ts [@types/koa]: Parameterize Context and Application. (#31704) 2018-12-31 10:35:34 -08:00
tsconfig.json
tslint.json