Search code examples
typescripttypeskoa

Adding to existing library typescript types with a new definition file


I’m using this library https://github.com/chentsulin/koa-bearer-token which adds an extra property to the koa libraries request object like ctx.request.token. So if I use the koa types directly I get an error which tells me the token property doesn’t exist on ctx.request.token.

My current solution

I created a type definition file called koa-bearer-token.d.ts which contains types for the library and exports for the extended koa context/request type:

declare module 'koa-bearer-token' {
    import {Context, Request, Middleware} from 'koa';

    interface Options {
        queryKey?: string;
        bodyKey?: string;
        headerKey?: string;
        reqKey?: string;
    }

    interface RequestWithToken extends Request {
        token?: string
    }

    interface ContextWithToken extends Context {
        request: RequestWithToken
    }

    export default function bearerToken(options?: Options): Middleware;
    export {RequestWithToken, ContextWithToken};
}

Then I use this in other files like:

import {ContextWithToken} from 'koa-bearer-token';
const someFunction = (ctx: ContextWithToken) => {
    const token = ctx.request.token; // <-- No longer errors
};

Why I'm asking this question

This works now but I’m concerned it isn’t the best way because it wouldn’t work if I need to add more properties in the future, ideally I want to just create a koa.d.ts file that adds to the libraries types then I can carry on using import {Context} from 'koa'; instead of import {ContextWithToken} from 'koa-bearer-token'; but when I create koa.d.ts it overwrites all the library types instead of adding on top of them.

Here is my tsconfig.json in case it helps

{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "es6",
    "noImplicitAny": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist",
    "baseUrl": ".",
    "paths": {
      "*": [
        "node_modules/*",
        "src/@types/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ]
}

Solution

  • You can try with module augmentation. You don't have to declare a new module. Typescript is going to merge both modules and you should have the legacy koa typings plus your new ones.

    import * as koa from "koa"
    declare module 'koa'{
        interface Request {
            token: string;
        }
    }
    
    declare const c: koa.Request;
    c.token = 'tre';
    

    The tricky thing is that it has to be placed just after the koa import. So, I would suggest to set this new change in a separated file so it is easy to apply your change everywhere.

    import * as koa from "koa";
    import '<path to>koachanges';
    

    Hope that helps

    Regarding you have said, I would say it is possible.

    Change your tsconfig in order to add a global d.ts file.

     ...
     "typeRoots": ["./node_modules/@types", "./typings"]
     ...
    

    Add an index.d.ts file in this new typings folder in the root directory of your project and place in it.

    import * as Koa from 'koa';
    declare module 'koa'{
        interface Request {
            token: string;
        }
    }
    

    It is important to add the first import as then is importing the koa typings to your global file and then you can override them.