5

PLEASE SEE MORE DETAILED QUESTION: How do I write a TypeScript declaration file for a complex external commonjs module that has constructor, such as imap?

I write TypeScript for a Node.js app, and I want to write a TypeScript declaration file for a javascript module (available from npm) that has a constructor at the module level.

Here is a simplified version of the relevant code, in file a.js:

function A(config) {
    this.state = 'constructed';
}
A.prototype.update = function() {
    this.state = 'updated';
};
module.exports = A;

and a simplified javascript application, app.js, that uses module a:

var mod = require('a');
var i = new mod({});
console.log('i.state=' + i.state);
i.update();
console.log('i.state=' + i.state);

How do I write a TypeScript declaration file for module a.js?

I've read the TypeScript Guide for Writing Definition (.d.ts) Files but unfortunately, I couldn't figure out how to apply the guidelines to this case.


updated to include interfaces

Here is my declaration file a.d.ts:

declare module 'a' {
    import events                           = require('events');
    import EventEmitter                     = events.EventEmitter;

    interface Config {
        foo: number;
    }
    interface Other {
        baz: number;
    }

    class A extends EventEmitter {
        state: string;
        constructor(config: Config);
        update(): void;
    }

    var out: typeof A;
    export = out;
}

I can't figure out how to make the interfaces available to my TypeScript app. I also want to keep them within the module, so that names like Config don't collide with those from other modules.


Added TypeScript app that uses this declaration

This is what I expect my app.ts to look like:

import mod = require('a');
import Config = mod.Config;
import Other = mod.Other;

var other : Other = {a: 2};
var config : Config = {foo: 2};
var i = new mod(config);
console.log('i.state=' + i.state)
i.update();
console.log('i.state=' + i.state)

2 Answers 2

3

There are a couple ways to do this, here is one:

declare class A {
    state: string;
    constructor(config: any);
    update(): void;
}

declare module 'a' {
    var out: typeof A;

    export = out;
}

EDIT: If you want to include interfaces, but also have an exported class, you can set it up like this:

declare module A {
    class A {
        state: string;
        constructor();
        update(): void;
    }

    interface B {
        value: any;
    }
}

declare module 'a' {
    var out: typeof A.A;

    export = out;
}
Sign up to request clarification or add additional context in comments.

4 Comments

I also tried moving the class declaration inside of the module (without the declare keyword), and that worked too.
I have a complication: How can I also define public interfaces in module a? It seems that the export = statment prevents this.
I can't get the answer with interfaces to work. I've added a typescript app.ts to the question. BTW, the compiler issues misleading error text in this case: "error TS2304: Cannot find name 'mod'.", when it cannot find Config or Other.
Thanks. This led me on the right path. I found another module, auth0, similar to the one I want to declare, and worked from the patterns there. Those patterns are similar to the ones you suggested.
1

I found an existing declaration file for a modules that has similar structure to the one for which I want to write a declaration file: auth0

I now have something that works, although not yet ideal. The declaration file a.d.ts is:

/// <reference path='node.d.ts' />
interface Config {
    foo: number;
}

declare module 'a' {
    import events                           = require('events');
    import EventEmitter                     = events.EventEmitter;

    class A extends EventEmitter {
        constructor(config : Config);
        state: string;
        update(): void;
    }
    var out: typeof A;
    export = out;
}

with the TypeScript app file app.ts being:

/// <reference path='a.d.ts' />
import mod = require('a');

var config : Config = {
    foo: 1
} 
var i = new mod(config);
console.log('i.state=' + i.state)
i.update();
console.log('i.state=' + i.state)

and the a.js module being as in the original question.

I compile this with: tsc --module commonjs app.ts

This certainly works for now.

Although I think it's messy to have the interface (Config) outside of the module, but I haven't yet figured out how to move the interfaces inside.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.