kristoffer_remback
kristoffer_remback

Reputation: 570

Typings: Type declaration for JS module exporting instance of class, with prototype of the class

I'm sorry if the title is confusing, I'm not entirely sure how to phrase it better.

I'm trying to wrap my head around writing type declarations by attempting to produce one for this file (which is the source for this npm module), wherein I basically export an instance of the Eventer class allowing the module to as a singleton but also contains a property referencing the class to create sandboxed instances. I'm using Visual Studio Code to check if the properties are correct. The module looks something like this:

// tiny-eventer.js

function Eventer () {
    this.on = function (eventName, listener) { ... };
    this.trigger = function (eventName, args) { ... };
}

Eventer.prototype.Eventer = Eventer;

module.exports = new Eventer();

In another module I can then use the singleton-like eventer instance by requiring it, but also create a sandboxed instance calling new eventer.Eventer().

// index.js

var eventer = require('tiny-eventer');

var sandboxedEventer = new eventer.Eventer();

sandboxedEventer.on('an-event', function (args) { console.log('sandboxed ' + args); });

eventer.on('an-event', function (args) { console.log('global ' + args); });

eventer.trigger('an-event', 'is called');
// Prints to console: "global is called"

sandboxedEventer.trigger('an-event', 'is called');
// Prints to console: "sandboxed is called"

This basically means this horrific piece of code is valid too:

// sorry.js

var eventer = require('tiny-eventer');
var otherEventer = new (new (new (new eventer.Eventer()).Eventer()).Eventer()).Eventer();

As for the typings I've tried the following:

declare module 'tiny-eventer' {
    ...

    interface TinyEventItem { listener: (args) => void }

    class Eventer {
        // Doesn't seem to work as it should
        Eventer: Eventer;

        on(eventName: String, listener: (args) => void): TinyEventItem;

        trigger(eventName: string, args: any): void;
    }

    export = new Eventer;
}

The above will work with the singleton properts such as eventer.on and eventer.trigger, but also seems to allow eventer.Eventer.on, whereby new eventer.Eventer() isn't allowed. It feels like I'm doing this wrong.

How would I got about writing a typings file which declares a class with a property referencing itself?

Upvotes: 0

Views: 103

Answers (1)

kristoffer_remback
kristoffer_remback

Reputation: 570

I figured out something that produces the result I'm looking for (in vscode's Intellisense at least), although I'm not sure it's a proper solution.

What solved it for me was the following Eventer: new Eventer;

If anyone has a better solution, please post them or update this.

declare module 'tiny-eventer' {
    ...

    interface TinyEventItem { listener: (args) => void }

    class Eventer {
        on(eventName: String, listener: (args) => void): TinyEventItem;

        trigger(eventName: string, args: any): void;

        // This right here seems to do it
        Eventer: new Eventer;
    }

    export = new Eventer;
}

Upvotes: 1

Related Questions