Search code examples
typescriptamd

How To Structure Extensions Within An AMD TypeScript Program


I am writing a program in TypeScript that mainly follows an AMD loading pattern whereby classes are loaded using an import statement.

import TestRunner = require('../TS/TestRunner');

I do, however, want to include some extension methods that extend objects such as NodeList - so there will be a small number of extension files that contain an extension to the lib.d.ts interfaces and then an implementation of the additional feature - for example...

interface NodeList {
    extensionMethod(...info): NodeList;
}

NodeList.prototype.extensionMethod = function (...info: string[]) {
    return this;
};

I could just include all the extensions at the start of my program so they are available - but I would actually like to load them on demand just like the rest of the code. The problem is, the file containing the extensions doesn't really export anything to use - it just adds this code to existing objects.

What is the best way to include the extensions in my TypeScript program?


Solution

  • Here's a setup that works. Key points:

    • You'll need to place the interface extensions in a file that is not an external module (otherwise you'll be declaring a new interface in the external module scope rather than extending the existing type).
    • This only works on objects defined at the global scope. Extending other objects' prototypes is dangerous enough already, so no big loss on that account.
    • You'll need to manually invoke require. For AMD scenarios, use the undocumented /// <amd-depdendency path="path" /> tag.
    • The file containing the extensions can be an external module if needed.

    myExtensions.d.ts

    // In case you're not using node.d.ts
    declare var process: process;
    
    interface process {
        getFour: any;
    }
    

    extensions.ts

    /// <reference path="myExtensions.d.ts" />
    
    process.getFour = () => 4;
    

    consumer.ts

    /// <reference path="myExtensions.d.ts" />
    
    // In case you're not using node.d.ts
    declare var require;
    
    // Manual import of extensions
    require('./extensions');
    
    console.log(process.getFour()); // Works