So I have a third-party SDK written as an oldschool IIFE based module. In other words it looks something like this:
var ThirdPartySDK = (function() {
var export = {};
// Add some methods to export
return export;
})();
You would then be expected to use it by referencing it on the global scope like this:
<html>
<body>
<script src="lib/ThirdPartySDK.js">
<script>
ThirdPartySDK.foo();
<\script>
<\body>
<\html>
I could still use it this way of course, but is that really the best practice with Angular and TypeScript? Is there some way to set things up with angular/TypeScript/webpack so that I can use a proper import statement? Something like this:
import { ThirdPartySDK } from '../lib/ThirdPartySDK.js';
ThirdPartySDK.foo();
So I have a third-party SDK written as an oldschool IIFE based module. In other words it looks something like this:
var ThirdPartySDK = (function() {
var export = {};
// Add some methods to export
return export;
})();
You would then be expected to use it by referencing it on the global scope like this:
<html>
<body>
<script src="lib/ThirdPartySDK.js">
<script>
ThirdPartySDK.foo();
<\script>
<\body>
<\html>
I could still use it this way of course, but is that really the best practice with Angular and TypeScript? Is there some way to set things up with angular/TypeScript/webpack so that I can use a proper import statement? Something like this:
import { ThirdPartySDK } from '../lib/ThirdPartySDK.js';
ThirdPartySDK.foo();
Share
Improve this question
edited Jan 17, 2019 at 17:27
Zac Delventhal
asked Jan 16, 2019 at 21:23
Zac DelventhalZac Delventhal
4,0104 gold badges23 silver badges27 bronze badges
2 Answers
Reset to default 6The best way to have a proper import statement for the actual value of ThirdPartySDK
is to refactor the script to a module that exports this value. The following snippet allows you to use the import statement as showed:
export const ThirdPartySDK = {
foo() { console.log('Doing foo'); }
};
For big libraries refactoring is not always that easy, so I see 2 approaches that do not involve too much refactoring:
1. Export the ThirdPartySDK
variable
You could simply make a module out of the IIFE file by exporting the current IThirdPartySDK
variable (returned by the IIFE), and then import it as you showed:
export const ThirdPartySDK = (function() {
var _export = {};
// Add some methods to export
return _export;
})();
Note that if you want to have some useful information about the shape of ThirdPartySDK
you would have to add a type annotation to the const
declaration, and if SomeType
(see below) does not yet exist you'll have to write it yourself:
export const ThirdPartySDK: SomeType = (function() {
// ...
At this point Typescript will start to plain about the IIFE expression not being assignable to SomeType; the quick 'solution' to tell typescript to pretend the expression evaluates to a value of type SomeType
using the as
keyword:
export const ThirdPartySDK: SomeType = (function() {
// ...
})() as SomeType;
2. Keep the <script>
tag and declare the variable
Another option it to keep the script tag, import nothing, and declare the variable and its expected type in typescript:
(But also in this case you might have to provide type definitions yourself)
interface SomeType {
// SDK type shape goes here...
}
declare const ThirdPartySDK: SomeType;
You can wrap the third-party SDK in a TypeScript module using a hack with eval
.
Let's say that ThirdPartySDK.js looks like this:
var ThirdPartySDK = (function () {
var exports = {
foo: function () { console.log("Hello, world!"); }
};
return exports;
})();
You would then create a ThirdPartySDK-wrapper.ts module that looks something like this:
import * as fs from 'fs';
const script = fs.readFileSync('../lib/ThirdPartySDK.js').toString();
global.eval(script);
//@ts-ignore
export default ThirdPartySDK;
The @ts-ignore
directive is required to keep the TypeScript piler from plaining about not finding a declaration for the ThirdPartySDK
variable (it is declared in the script executed through eval
).
You can then import ThirdPartySDK through the wrapper module:
import ThirdPartySDK from './wrapper';
ThirdPartySDK.foo(); // Console output: "Hello, world!"
Note that this wrapper only works for applications running in Node.js, since it uses fs.fileReadSync
to get the contents of the script.
If you're going to use it in a browser, you will need some other way to retrieve the script. You could probably use frameworks such as WebPack to bundle the ThirdPartySDK script as a string value that you can require
in the wrapper module.