Reputation: 2055
I'm authoring an npm module in TypeScript https://www.npmjs.com/package/html2commonmark. The module can be used in nodejs (by using require
) and from the browser (by loading node_modules/html2commonmark/dist/client/bundle.js
in your browser).
I've recently added the *.d.ts files in order to get typing information when using "moduleResolution": "node"
. This works great, when installing my module it is ready to be used in typescript. Thus: the following piece of typescript code is compiling without errors:
// After installing using npm install html2commonmark
// using "moduleResolution": "node"
import * as html2commonmark from 'html2commonmark';
let converter = new html2commonmark.JSDomConverter();
Beautiful!
Now i want to run my module in a browser. As mentioned before, i need to add a script tag to node_modules/html2commonmark/dist/client/bundle.js
to my index.html page. After that, the html2commonmark global variable should be available. The problem is: how do i let the typescript compile know that the global variable is there? The following piece of TS code won't compile:
let converter = new html2commonmark.BrowserConverter();
// error TS2304: Cannot find name 'html2commonmark'.
Even if i add a global.d.ts file, I don't seem to be able to both import my external module and declare my global variable:
// Something like this does not work :(
import * as b from 'html2commonmark';
declare var html2commonmark: typeof b;
I understand why this is. By using the import keyword my ts file is converted to an external module and thus needs to be imported. Yet i feel like my scenario is a common one. Namely: an npm module containing both an npm component and the bundle for the browser which exposes the functionality as a global variable.
Is there any way to declare the global variable using the definition inside my external module? I don't feel like rewriting my api as a (DefinitelyTyped-style) namespace while i just written my entire source code in TS...
Upvotes: 2
Views: 3082
Reputation: 18766
The correct ways to write an external module that works in both a browser and in Node.js is:
--module umd
flag and then use an AMD loader in the browser to load the module--module commonjs
flag and then use a bundler like webpack or browserifyIn other words, when you start writing modular code, blindly adding <script>
tags to an HTML file is no longer the correct way to load that code into a browser. Just as you should not touch the global scope in Node.js, so too should you not touch the global scope in a browser. You could hack it with a if (typeof window !== 'undefined') (<any>window).global = yourObject;
, but seriously, don’t ever do this, it is wrong and it will break.
As far as exposing interfaces from within external modules to a global scope, there is no way to do this, since you would have to As of TypeScript 1.8, you can augment global types from inside modules by using import
the external module to get a reference to its interfaces, at which point you’ve created another external module.declare global
.
Upvotes: 2