Adding to existing library typescript types with a new definition file
Asked Answered
C

3

14

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/**/*"
  ]
}
Calices answered 12/7, 2018 at 5:1 Comment(0)
M
17

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.

Megohm answered 12/7, 2018 at 6:4 Comment(2)
Thanks @kimy82! So there's no way to augment the koa types globally in a koa.d.ts file? It seems odd that I can't do that, say even if I wanted to add types to DefinitelyTyped for koa-bearer-token would there be no way available to sub-library authors to add properties. So everytime anyone installs a sub-library like koa-bearer-token the properties the sub-library adds would always be incorrectly typed?Calices
Thank you for the updated answer, that's worked! I initially named my file to koa.d.ts which still overwrote all the koa types but naming it something like koa-extensions.d.ts and importing Koa as per the answers example fixed the issue. For more info, I also just came across this issue which is highly relevant github.com/Microsoft/TypeScript/issues/10859Calices
C
3

An alternate more extensible solution to adding the types to koa-bearer-token.d.ts would be to add a file like koa-extensions.d.ts and add any extra properties there like so:

import {Context, Request} from 'koa';

declare namespace KoaExtensions {
    interface KoaRequest extends Request {
        token?: string
    }

    interface KoaContext extends Context {
        request: KoaRequest
    }
}

export = KoaExtensions;

Then the extended types can be imported:

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

This is an improvement on my initial solution but it still seems like I should be able to globally augment the Koa module types in a local koa.d.ts file.

Calices answered 12/7, 2018 at 7:26 Comment(0)
E
0

I needed to do the same to add something to Knockout. I created a my-ko-additions.d.ts file and implemented it in the same way the Knockout declarations are done:

interface KnockoutStatic {
    additionalFunc1(input: string): string;
    additionalFunc2(input: string): string;
}

declare var ko: KnockoutStatic;

declare module "knockout" {
    export = ko;
}

Then I can implement and use these functions by just saying ko.additionaFunc1('abc').

Eldwun answered 18/6, 2019 at 21:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.