Setting the Stage:
In the process of shifting a hefty ~3,000 line inline <script>
from a web-page to a TypeScript file (PageScripts.ts
) to be utilized by the page through
<script src="PageScripts.js" defer></script>
.
This script entails SortableJS which boasts an available @types
package. You can access the *.d.ts
files on GitHub here: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/sortablejs
The Original Script Snippet:
Here's a snippet from the original JavaScript in the HTML page causing issues:
<script type="text/javascript">
window.addEventListener( 'DOMContentLoaded', function() {
var sortableOptions = {
dataIdAttr: 'my-id',
onEnd: function( ev ) {
// do stuff
}
};
} );
</script>
I incorporated the @types by executing
npm install --save @types/sortablejs
.
My tsconfig.json
resembles this:
{
"compileOnSave": true,
"compilerOptions": {
"noImplicitAny": true,
"strict": true,
"noEmitOnError": true,
"removeComments": true,
"sourceMap": true,
"target": "es5" /* es5 for IE11 support. */,
"typeRoots": [
"node_modules/@types",
"JSFiles/System.Web.dll/Types"
],
"lib": [
"es5",
"dom",
"dom.iterable",
"es2015.core",
"es2015.collection",
"es2015.symbol",
"es2015.iterable",
"es2015.promise"
]
},
"exclude": [
"node_modules"
]
}
Transitioning to TypeScript:
The aforementioned script fragment was transformed into TypeScript in PageScripts.ts
:
import Sortable = require("sortablejs");
// ...
window.addEventListener( 'DOMContentLoaded', function() {
var sortableOptions = {
dataIdAttr: 'my-id',
onEnd: function( ev: Sortable.SortableEvent ) {
// do stuff
}
};
} );
This compiles without errors, but due to the single import
statement, TypeScript compiles the file as its JavaScript module, rendering it incompatible for direct use in web-pages. TypeScript appends this line to the beginning of the output PageScripts.js
file:
Object.defineProperty(exports, "__esModule", { value: true });
This provokes a browser script error as exports
is not defined.
To counter this, I opted for
/// <reference types="sortablejs" />
:
/// <reference types="sortablejs" />
// ...
window.addEventListener( 'DOMContentLoaded', function() {
var sortableOptions = {
dataIdAttr: 'my-id',
onEnd: function( ev: Sortable.SortableEvent ) { <--- "Cannot find namespace 'Sortable'."
// do stuff
}
};
} );
However, PageScripts.ts
fails to compile as tsc
throws a "Cannot find namespace 'Sortable'" error.
The IDE suggests importing
import Sortable = require("sortablejs")
as the fix, yet this reverts PageScripts.js
back to a module, causing frustration!
Changing module: 'none'
in tsconfig.json
is not an option as other TypeScript files in the project are modules and altering global settings is undesirable. Is there a way to configure per-file modules?
The Dilemma:
Hence, the big question: How can I utilize the types from @types/sortablejs
without transforming my PageScripts.js
into a module?