bubbleking
bubbleking

Reputation: 3611

Making a TypeScript Declaration for Existing JavaScript

A former colleague wrote a small chunk of JavaScript (I'm not even sure what to call it. Class? Library?) which I'm now trying to use in a TypeScript portion of our application. We've had some similar situations where we merely added some kind of declaration to a d.ts file. I'm trying to do that now, but I'm getting hung up on the fact that the object I want to use is also a function in the original JS. That is, it is created via the new operator, yet the constructed object has methods. I'm hoping someone can tell me the best approach for this.

Here is the original JavaScript class/library:

(function (geographies, $) {
    geographies.map = function(elementId) {
        var self = this;
        // Other members elided

        // Public Functions
        self.findAddress = function (addressDesc, callback){
            // elided
        }

        // Other public methods elided


        // Private Methods
        function _example() {
            // elided
        }

        // Other private methods elided
    }
}(window.geographies = window.geographies || {}, jQuery));

Of course, this results in geographies being created in the global window namespace, and geographies has a member, map which has methods, but is created via new with a string parameter passed in. Here's an example of geographies.map being used in existing code (in this context, self merely refers to a containing component):

if ((self.editAddress.cityId() && self.editAddress.addressLine1())) {
    if (map === null) {
        map = new geographies.map("addressMapDiv");
    }
    self.mapVisible(true);
    var query = (self.editAddress.addressLine1() ? self.editAddress.addressLine1() : "") +
        (self.editAddress.cityDescription() ? " " + self.editAddress.cityDescription() : "") +
        (self.editAddress.zipCode() ? " " + self.editAddress.zipCode() : "");
    console.log(query);
    map.findAddress(query);
}

Now we're starting to use geographies in TypeScript and thus want some way to get Intellisense and type-checking on it, but there is no plan to reimplement it. We merely want TypeScript to give us a way to use what will be the same object in the window namespace that already exists. I've taken a few cracks at it, but none have seemed to quite make sense. I think the biggest problem is that geographies.map needs to be newable and accept the string parameter elementId , while also becoming an object with methods of its own. Here is my latest failed attempt:

interface Map {
    constructor(elementId: string): Map;
    findAddress(addressDesc: any, callback: any): any;
    // Other signatures elided
}

interface GeographiesStatic {
    map: Map;
    // Other members elided
}

declare var geographies: GeographiesStatic;

Should I be using declare class? Interfaces? Do I need the declare var at the bottom, or will that somehow kill the object of the same name that's already in the window namespace? Any guidance would be appreciated.

Upvotes: 1

Views: 124

Answers (1)

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 221014

The code uses the revealing module pattern, which is usually represented with namespace in TypeScript. An easy declaration for this file would be:

declare namespace geographies {
  class map {
    constructor(name: string);
    findAddress(desc: any, cb: any): any;
  }
}

Upvotes: 3

Related Questions