By using
exportandimport(a.k.a. EcmaScript Module -ESM-), TypeScript unifies the way modules depend upon each other. For example, Node.js ☛requirekeyword (a.k.a."CommonJS"module) is no longer useful and thus used in TypeScript.Based on the value of
modulekey 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,deferetc.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 importRule(s)
- The way
exportandimportwork 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,
exportandimportare 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
importlooks for.jsfiles, TypeScriptimportlooks for.tsfiles!- One may choose that no entity is imported. For example,
importincludes (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.jsonand next TypeScript)"dependencies": {…, "lodash": "^4.17.20", …}, "devDependencies": {…, "@types/lodash": "^4.14.168", …},import {pick} from "lodash";Rule(s)
- TypeScript declaration files (
.d.tssuffix) 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;
declarekeyword may help. Indeed,declareis 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.jsonmay 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.jsfile 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.jsfile is loaded within HTML.- Later on,
UV_mapping_three.jsmust then load what it requires, namely three.js. Note that therequire.js,three.jsandUV_mapping_three.jsfiles are together stored in ajssub-directory of the directory in whichindex.htmlis 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
--outFilecompiler 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
exportandimport.export namespace SCION { export interface Event { … } export interface State { … } … } … import {SCION} from "./SCION_CORE"; … const state: SCION.State = …