DefinitelyTyped/types/koa-compose/index.d.ts
Anton Astashov 66001ee764 [@types/koa-compose]: Provide way for typesafe compose
Right now it's impossible to compose a bunch of middlewares, and
preserve their state/context type. It will be either erased and
converted to `any`, or will show an error.

For example, we have 3 middlewares:

```ts
type FooCtx = { foo: string };
type BarCtx = { bar: string };
type WooCtx = { woo: string };

const fooMiddleware: Koa.Middleware<FooCtx, {}> = async (ctx, next) => {
    ctx.state.foo = 'foo';
    await next();
};
const barMiddleware: Koa.Middleware<BarCtx, {}> = async (ctx, next) => {
    ctx.state.bar = 'bar';
    await next();
};
const wooMiddleware: Koa.Middleware<WooCtx, {}> = async (ctx, next) => {
    ctx.state.woo = 'woo';
    await next();
};
```

If we try to compose them together, we'll get an error:

```ts
const composed = compose([fooMiddleware, barMiddleware, wooMiddleware]);
// types of params context and context are incompatible
// Type ParameterizedContext<FooCtx, {}> is not assignable to
// ParameterizedContext<BarCtx, {}>
```

We can shut it up by providing `<any>` type parameter, but that will
erase their types:

```ts
const composed = compose<any>([fooMiddleware, barMiddleware, wooMiddleware]);
// `composed` type is `compose.ComposedMiddleware<any>`.
```

As a solution, I don't think there's a way to do typesafe `compose` for
variable number of middlewares, but we can overload `compose` and make a
typesafe one for 2 middlewares. You can then compose `compose`s to
compose more than 2 middleares :) Like, instead of:

```ts
compose([fooMiddleware, barMiddleware, wooMiddleware])
```

It will be:

```ts
compose([fooMiddleware, compose([barMiddleware, wooMiddleware]))
// `composed` type is `Middleware<ParameterizedContext<FooCtx & BarCtx & WooCtx, {}>`
```

What do you think?
2019-01-31 09:57:41 -06:00

21 lines
712 B
TypeScript

// Type definitions for koa-compose 3.2
// Project: https://github.com/koajs/compose
// Definitions by: jKey Lu <https://github.com/jkeylu>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
import * as Koa from "koa";
declare function compose<T, U, V, W>(
middleware: [Koa.Middleware<T, U>, Koa.Middleware<V, W>]
): Koa.Middleware<T & V, U & W>;
declare function compose<T>(middleware: Array<compose.Middleware<T>>): compose.ComposedMiddleware<T>;
declare namespace compose {
type Middleware<T> = (context: T, next: () => Promise<any>) => any;
type ComposedMiddleware<T> = (context: T, next?: () => Promise<any>) => Promise<void>;
}
export = compose;