Search code examples
typescriptmoduletypescript-typingsrollupumd

What is the fastest way to generate a .d.ts file for a browser version of a library?


I have a quite large library written in Typescript 2.3.4 that is exporting a lot of ES6 modules and classes. I now need to use the library in an older browser app, written in typescript but using internal modules only. I managed to build a browser version of the library (thus polluting the global namespace) using rollup, and it works fine, at run time !

My problem now is to generate the typings (.d.ts) for the library when used as a global.

My code is compiled starting from a single index.ts file containing something like this:

import * as Promises from "./Promises";
export { Promises };

import * as CommonInterfaces from "./CommonInterfaces";
export { CommonInterfaces };

import * as Utils from "./Utils";
export { Utils };

import * as DomainEvents from "./DomainEvents";
export { DomainEvents };
...

I build the library in es6 modules and then use rollup to obtain a monolithic umd file that when loaded in a browser environment creates a single property called DDDTools in the "window" global, containing all of the modules exported, like this

window.DDDTools
            +-- Promises
            +-- CommonInterfaces
            +-- Utils
            +-- DomainEvents
            +-- ...

this is exactly what I would obtain if I developed the library using internal modules (namespaces) instead of external modules.

Since the library is developed using external modules I can't use the d.ts files generated by the tsc compiler which are containing something like this (for the Utils module):

file: Utils/index.d.ts

export { ObjectIterator } from "./ObjectIterator";
export { SimpleGuid } from "./SimpleGuid";
export { SimpleIdentityMap } from "./SimpleIdentityMap";

taking the object iterator as an example

file: Utils/ObjectIterator.d.ts

export interface IObjectIteratorItem {
    value: any;
    propertyNameOrIndex: string;
    parentObject: any;
}
export declare class ObjectIterator {
    private srcObject;
    private knownObjects;
    private toBeTraversed;
    private traversed;
    private currentStackItem;
    constructor(srcObject: any);
    hasNext(): boolean;
    getCurrent(): IObjectIteratorItem;
    moveNext(): void;
    reset(): void;
    private isKnownObject(obj);
    private addToKnownObjects(obj);
    private addToStack(obj);
}

these .d.ts are fine if I use the library in my typescript sources as external modules, so I can write

/* fine, but make*/
import { ObjectIterator } from "DDDTools/Utils";  

let oi = new ObjectIterator( ... // <-- and here my editor would show all the intellisense that makes typescript really cool ;)

BUT how do I say to typescript that exists a global whose name is DDDTools and that contains all the modules it exports ?

My first try was:

import * as dddtools from "DDDTools";
declare var DDDTools: dddtools;

but this makes my file an external module, and my poor browser app (containing a lot of files) is still namespace based (internal modules), doesn't compile anymore.

I think I need a way to create a .d.ts containing something like this

declare namespace DDDTools.Utils {
    export interface IObjectIteratorItem {
        value: any;
        propertyNameOrIndex: string;
        parentObject: any;
    }
    export declare class ObjectIterator {
        private srcObject;
        private knownObjects;
        private toBeTraversed;
        private traversed;
        private currentStackItem;
        constructor(srcObject: any);
        hasNext(): boolean;
        getCurrent(): IObjectIteratorItem;
        moveNext(): void;
        reset(): void;
        private isKnownObject(obj);
        private addToKnownObjects(obj);
        private addToStack(obj);
    }
}

Am I right ? If yes is out there a way to make it "automatically" ? I tried using tsc with the module option set to "system" (or amd) and outputting everything to a single file with the outFile option, but got something like this:

declare module "DDDTools/Utils/ObjectIterator" {
    export interface IObjectIteratorItem {
        value: any;
        propertyNameOrIndex: string;
        parentObject: any;
    }
    export class ObjectIterator {
        private srcObject;
        private knownObjects;
        private toBeTraversed;
        private traversed;
        private currentStackItem;
        constructor(srcObject: any);
        hasNext(): boolean;
        getCurrent(): IObjectIteratorItem;
        moveNext(): void;
        reset(): void;
        private isKnownObject(obj);
        private addToKnownObjects(obj);
        private addToStack(obj);
    }
}
... and so forth for each ES6 module I created

which is really really near to what I need, if only that declare module "DDDTools/Utils/ObjectIterator" could become a declare namespace DDDTools.Utils.ObjectIterator ... but you know it isn't

Any help would be greatly appreciated!


Solution

  • What is the fastest way to generate a .d.ts file for a browser version of a library?

    The fastest way is to just embrace the NPM ecosystem and let something like webpack do the bundling.

    More

    outFile is just pain that everyone can live without https://basarat.gitbooks.io/typescript/docs/tips/outFile.html so you will not find tooling that solves a broken code base. Better to fix the codebase instead of writing tooling to pile on to an unmaintainable system.