Reference module when overloading a global function in Typescript

Viewed 527

I'm using moment.js (specifically, moment-timezone) which has an interface called Duration. Duration.prototype.valueOf() returns a number, so in JavaScript, calling

setInterval(myCallback, moment.duration(30, 'seconds'));

works just fine.

I want to write a TypeScript declaration file that allows this.

global.d.ts

export {};

declare global {
    function setTimeout(callback: (...args: any[]) => void, ms: Duration, ...args: any[]): NodeJS.Timeout;

    function setInterval(callback: (...args: any[]) => void, ms: Duration, ...args: any[]): NodeJS.Timeout;
}

When I prepend

import { Duration } from 'moment-timezone';

it treats the .d.ts file as a module declaration, and so it doesn't affect the global namespace.

I thought to move the import inside the declare global scope, but it still treated Duration as any.

I've also tried

/// <reference path="node_modules/@types/moment-timezone/index.d.ts" />

but that doesn't seem to do anything.

I've seen a few answers that mentioned something about a setting in tsconfig.json, but that's not an option for me and this really seems like something that should just be possible in the first place.

1 Answers

This requires two steps:

  1. Declare the module outside the declare global scope.
  2. Place imports inside the declare global scope.

For the OP example:

export {}

declare module 'moment-timezone';

declare global {
    import { Duration } from 'moment-timezone';

    function setTimeout(callback: (...args: any[]) => void, ms: Duration, ...args: any[]): NodeJS.Timeout;

    function setInterval(callback: (...args: any[]) => void, ms: Duration, ...args: any[]): NodeJS.Timeout;
}

If you want to import your own types into an external module, place the import inside the declare module scope, and make sure your types are within a declare module scope of their own.

typings/my-custom-types.d.ts

declare module 'my-custom-types' { // <-- this was the missing line that was giving me trouble
    export interface MyStringInterface {
        valueOf(): string;
    }
}

typings/some-lib/index.d.ts

declare module 'some-lib' {
    import { MyStringInterface } from 'my-custom-types';

    export interface SomeExistingClass {
        // Add your own signatures
        someExistingMethod(stringParam: MyStringInterface): any;
    }
}
Related