By using
export
andimport
(a.k.a. EcmaScript Module -ESM-), TypeScript unifies the way modules depend upon each other. For example, Node.jsrequire
keyword (a.k.a."CommonJS"
module) is no longer useful and thus used in TypeScript.Based on the value of
module
key intsconfig.json
(e.g.,"module": "CommonJS"
), TypeScript generates JavaScript code following a module system standard:"CommonJS"
,"ES6"
,"ESNext"
, or any other.
Rule(s)
- Old-fashion JavaScript style invites us to load (in sequence) source code within HTML files, starting from external libraries to homemade code. Such a method implies a lot of manual management: sequence must respect dependencies, asynchronous loading (for performance) must be explicit using
async
,defer
etc.Example
<!DOCTYPE html> <html> <head> … <script src="js/chai.js"></script> <script src="js/dat.gui.min.js"></script> <!-- Loading based on Content Delivery Network -CDN-: --> <script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script> <!-- My stuff: --> <script src="js/Homemade_code.js"></script> <script> if (typeof chai === "undefined") window.alert("STOP: it won't work because 'chai.js' has not been loaded…"); if (typeof dat === "undefined") window.alert("STOP: it won't work because 'dat.gui.min.js' has not been loaded…"); if (typeof createjs === "undefined") window.alert("STOP: it won't work because 'createjs-2015.11.26.min.js' has not been loaded…"); window.onload = go; // 'go' function must exist in 'js/Homemade_code.js' file... </script> </head> <body > <canvas id="my_canvas" width="600" height="400"></canvas> </body> </html>
Nice Web sites for Content Delivery Network -CDN- are cdnjs, jsdelivr, or unpkg.
Example
<!DOCTYPE html> <html> <head> … <script type="module"> import { unaryTest, evaluate } from 'https://unpkg.com/feelin@3.0.0?module'; console.log(unaryTest('1', { '?': 1 })); </script> </head> <body > … </body> </html>
export
and import
Rule(s)
- The way
export
andimport
work in TypeScript is similar to JavaScript 6.Example (PURE JavaScript, using RequireJS)
<!-- 'data-main' attribute tells 'require.js' to load 'UV_mapping_three.js' after 'require.js' loads... --> <!-- *By construction*, 'UV_mapping_three.js' is loaded in an asynchronous way by 'require.js' --> <!-- Here, 'async' just embodies the asynchronous loading of 'require.js' itself! --> <script async data-main="./js/UV_mapping_three" src="./js/require.js"></script>
requirejs(['three'], function (library) { window.THREE = library; // While 'three.js' may be used from here, one has however to check that the DOM and/or the full window (images, sounds, videos…) are/is loaded. });
Rule(s)
- From JavaScript 6,
export
andimport
are native supports to manage modules and their dependencies (see also here…).Example (PURE JavaScript) UV_mapping_three_js.zip
<script src="./js/UV_mapping_three.js" type="module"></script>
/** FB_ei.js */ // 'use strict'; // No need when imported... export var author = {value: "Franck Barbier"}; export default getAuthor; // Only one default export, i.e., import does not require braces! function getAuthor() { return author.value; };
/** Authoring_ei.js */ // 'use strict'; // No need when imported... import {author as developer} from "./FB_ei.js"; // '.js' is mandatory! import getAuthor from "./FB_ei.js"; export {Authoring}; // <=> {Authoring as Authoring}; var Authoring = function () { this._author = developer.value ? developer.value : getAuthor(); … };
Example (PURE JavaScript)
export class C {…} // 'export' must be synch with class declaration!
Rule(s)
- There is a way of instrumenting transitivity.
Example (PURE JavaScript) Export_import.js.zip
<script src="./js/C.js" type="module"></script>
// 'A.js' file export let A = "A";
// 'B.js' file import {A as proxy} from "./A.js"; export let A = proxy;
// 'C.js' file import {A} from "./B.js"; window.alert("'A' in 'C.js': " + A); // "A" is displayed...
Rule(s)
- While JavaScript
import
looks for.js
files, TypeScriptimport
looks for.ts
files!- One may choose that no entity is imported. For example,
import
includes (and thus triggers) code execution.Example
// 'index.ts' file is imported and contained code is executed: import './persistence'; // Make database accessible and running...
Example (Node.js)
import * as HTTP from "http"; // Pure TypeScript style...
Rule(s)
- Homemade JavaScript types from libraries are uncheckable types for the TypeScript compiler. The best way of solving the problem is the installation of a TypeScript-compliant declaration of the said types (if it exists) in a given library.
Example (
package.json
and next TypeScript)"dependencies": {…, "lodash": "^4.17.20", …}, "devDependencies": {…, "@types/lodash": "^4.14.168", …},
import {pick} from "lodash";
Rule(s)
- TypeScript declaration files (
.d.ts
suffix) are reserved for creating a compilation bridge from JavaScript to TypeScript.import * as THREE from "../three.js-r115/src/Three" // Look for 'Three.ts' or 'Three.tsx' or 'Three.d.ts'...
Rule(s)
- No TypeScript-compliant declaration of homemade types imposes bypassing TypeScript type checking;
declare
keyword may help. Indeed,declare
is used to tell TypeScript that the variable has been created elsewhere.Example
declare const dat; // Type is 'any'... console.assert(typeof dat !== "undefined", "Problem: it won't work because 'dat.gui.min.js' library has not been loaded...");
Rule(s)
- Contextual errors may be bypassed as well.
Example Covid-19_three_js.ts.zip
// @ts-ignore (no TypeScript support for 'THREE.GLTFLoader') -> compilation error disappears! (new THREE.GLTFLoader()).load('./models/Coronavirus-sars-co-v2.gltf', this._post_process_Covid_19.bind(this, ready)); // External lib.
Rule(s)
- To promote homemade types as checkable types, the
"types"
(≡"typings"
) key inpackage.json
may be used for publishing these types.Example (
package.json
)"typings": "dist/API.d.ts",
Rule(s)
- Browserify, Parcel, RequireJS, or webpack are utilities that allow packaging to simplify loading. In this scope, considering the
UV_mapping_three.js
file as the main (program) file of a simple Web application. This application reuses the three.js 3D library as a dependency. Using RequireJS as packager, only therequire.js
file is loaded within HTML.- Later on,
UV_mapping_three.js
must then load what it requires, namely three.js. Note that therequire.js
,three.js
andUV_mapping_three.js
files are together stored in ajs
sub-directory of the directory in whichindex.html
is located.
import
and export
, but namespaces may increase the way of organizing code as well
(see also here…).
Example Miscellaneous.ts.zip
// 'Namespace_Forname.ts' file namespace Forname { export const my_forname = "Joseph"; } namespace Nickname { export const my_nickname = "Jojo"; }
// 'Namespace_Surname.ts' file /// <reference path="./Namespace_Forname.ts" /> // 'Nickname' namespace is referenced... namespace Surname { // 'export' required to access namespace's properties in 'window.alert': export const my_surname = "Barbier--Darnal"; } namespace Nickname { // This namespace crosses 2 files... // 'export' required to access namespace's properties in 'window.alert': export const my_nickname_ = "Jo"; // Conflict with 'my_nickname'... } window.alert(Forname.my_forname + " " + Surname.my_surname + " as " + Nickname.my_nickname + " or " + Nickname.my_nickname_);
Rule(s)
- Packaging relies on the
--outFile
compiler option. Differently (no packaging), “common” script loading style may be used.Example (generated JavaScript files are loaded in sequence)
<script src="./Namespace_Forname.js"></script> <script src="./Namespace_Surname.js"></script>
Rule(s)
- Access to namespaces simply occur with
export
andimport
.export namespace SCION { export interface Event { … } export interface State { … } … } … import {SCION} from "./SCION_CORE"; … const state: SCION.State = …