TypeScript example using RequireJS
1. TypeScript with RequireJS
In this article we are going to explain how to create a TypeScript application and separate its components in modules. After that we are going to show how to load these modules using AMD with RequireJS and the TypeScript compiler options to support it.
All code and examples used in this tutorial are available in the download section at the end of this article.
Before starting with the article you need to install NodeJS in your system. Instructions can be found here: https://nodejs.org/en/.
Table Of Contents
2. RequireJS
RequireJS is an AMD JavaScript library that supports asynchronous file and module loading. It is optimized for web browser usage but it is also possible to use in Java or Node environments. It is compatible with all main browsers and quite intuitive to use. Its main benefit is that it offers the option to logically structure an application following the AMD principles.
In the article https://www.webcodegeeks.com/javascript/requirejs/requirejs-tutorial-how-to-use-requirejs/ you can find more information about how to use RequireJS.
3. TypeScript
TypeScript is a free and open source programming language created and supported by Microsoft. It enhances basic JavaScript with Object Oriented capabilities like object typing and classes support. Applications writen in TypeScript need to be transcompiled to JavaScript. The compiler is called tsc
and code written in TypeScript can be compiled to JavaScript in almost any JavaScript engine like NodeJS or a Browser, in this example we are going to use NodeJS to compile the application.
As we said before we are going to install TypeScript using NodeJS, in order to do that, you can type:
npm install -g typescript
To check that the installation has been successfull please type tsc
in your console and something like the following should appear:
Version 1.8.10 Syntax: tsc [options] [file ...] Examples: tsc hello.ts tsc --out file.js file.ts tsc @args.txt Options: --allowJs Allow javascript files to be compiled. --allowSyntheticDefaultImports Allow default imports from modules with no default export. This does not affect code emit, just typechecking. --allowUnreachableCode Do not report errors on unreachable code. --allowUnusedLabels Do not report errors on unused labels. -d, --declaration Generates corresponding '.d.ts' file. ...
A good explanation and overview about TypeScript can be found in https://en.wikipedia.org/wiki/TypeScript.
4. Creating a TypeScript project with NodeJS
In order to create our application we type the following
npm init
and we accept all options that are prompted (in case you want to modify some, fell free to do it).
We edit the package.json file and include the following to indicate a TypeScript dependency:
package.json
//check download section to see JS code "dependencies": { "typescript": "^1.8.10" }
After that we edit again the package.json and add a new script to run the TypeScript compiler tsc
:
package.json
//check download section to see complete JSON "scripts": { "test": "test", "tsc_amd": "tsc --module amd Game.ts" },
We will explain later what options we are passing to the compiler.
5. Modules in TypeScript
Modules is all about scoping. That is classes, methods, functions, etc. declared in the scope of a module are not visible outside this scope. In order to make them visible they need to be exported. The same applies for using this variable, function, class, method, whatever outside this module: it needs to be imported.
Modules features can be exported in one of the following ways:
- using the keyword
export
, like in:
nofile.js
//check download section to see similar JS code export const name = "dani";
- using export statements, for example:
nofile.js
//check download section to see similar JS code class Saluter{ hi(s: string) { return "hello " + name; } } export { Saluter}; export { Saluter as MySaluter };
- using
export =
, in this caseimport let = require("module")
needs to be used. This option will be used in the article. For example:
nofile.js
//check download section to see similar JS code class Salute{ hi(s: name) { return "hello " + name; } } export = Salute;
nofile.js
//check download section to see similar JS code import salute = require("./Salute"); let saluter= new salute(); console.log(saluter.hi("Dani");
Imports can be done in one of the following ways:
- Import a single export from a module
nofile.js
//check download section to see similar JS code import { Salute} from "./Salute"; let salute = new Salute();
- Import the entire module into a single variable, and use it to access the module exports
nofile.js
//check download section to see similar JS code import * as saluter from "./Salute"; let sal = new saluter.Salute();
Once we know how to create modules in TypeScript and how to export and import them and their properties, we need to generate them by indicating the tsc compiler what module target we are going to use. Possible targets are:
- CommonJS (for NodeJS apps)
- AMD / RequireJS
- UMD
- SystemJS
- ECMAScript 2015 native modules
The target is indicated to the compiler with the option --module
, like:
tsc --module
In this article we are going to show how to generate modules for AMD RequireJS based applications. This can be done by typing:
tsc --module amd
In order to generate just one output file the option outFile
can be used in combination with the --module amd
shown before.
This is just a brief explanation to support our example. For more information about modules in TypeScript please visit https://www.typescriptlang.org/docs/handbook/modules.html.
6. Example
In this chapter we are going to apply all this theory. We are going to create a TypeScript application divided in different files containing different modules that need to work with each other. Then we are going to launch the application without any module target and we are going to see what happens. Finally we are going to generate the application to run using RequireJS as module target using the compiler options explained before.
Here are some of the classes used in the application (you can download all of them in the download section of this article). Game.ts contains the code needed to play a game between two teams:
Game.ts
//check download section to see JS code import Team = require("Team"); class Game{ home: Team; away: Team; date: number;//epoch location: string; constructor(home?:Team, away?:Team, date?: number, location?: string){ if(home != null){ this.home = home; }else{ this.home = new Team(); } if(away != null){ this.away = away; }else{ this.away = new Team(); } if(date != null){ this.date = date; }else{ this.date = 1000; } if(location != null){ this.location = location; }else{ this.location = 'Carlos Tartiere, Oviedo'; } } toString(){ return this.home.name + " against " + this.away.name + " at " + this.date + " in " + this.location; } } export = Game;
Team.ts containing a coach, a director and a bunch of players per team:
Team.ts
//check download section to see JS code import Coach = require("Coach"); import Director = require("Director"); import Player = require("Player"); class Team { name: string; coach:Coach; director:Director; players:[Player]; generateRandomPlayers() { this.players = [new Player(), new Player(), new Player(), new Player(), new Player(), new Player(), new Player(), new Player(), new Player(), new Player(), new Player()]; } constructor() { this.name="Real Oviedo"; this.coach = new Coach(); this.director = new Director(); this.generateRandomPlayers(); } } export = Team;
A Player abstraction:
Player.ts
//check download section to see JS code import Person = require("Person"); class Player implements Person { firstName: string; lastName: string; age: number; country: string; goals: number; caps: number; constructor (){ this.firstName = "Andres"; this.lastName = "Iniesta"; this.age = 31; this.country = 'Spain'; this.goals = 22; this.caps = 100; } } export = Player;
Here we show a small snippet from the index.html where the require.js file is launched and initialized using the configuration file main.js and the game is initialized and started by requiring its entry point using RequireJS require function and calling its main method. Other files are not shown since they do not add any value to the article, as said, you can download them at the end of this tutorial:
index.html
//check download section to see JS code <script src="require.js" data-main="main.js"></script> </body> <button class="play" value="play" onclick="play();">play</button> <script> function play() { require(['Game'], function (Game) { var game = new Game(); console.log(game.toString()); }); } </script>
We can generate the application typing:
npm run tsc_amd
This launches the tsc compiler with the needed options to generate AMD RequireJS compatible JavaScript files, as stated in our package.json file. Now we can launch the index.html in our browser, click the button and check what happens in the console. I recommend to debug the application to check what files are loaded and how the files have been generated.
In combination with --module amd
you can use --outFile file
to combine all output in one file, something like:
tsc --module amd --outFile GameCompact.js Game.ts
So all required content is available in the new file GameCompact.js. The tsc options listed above can be entered in the package json file as a new script. This provides us more flexibility. Here is how the npm configuration package.json file looks like (I repeat, everything can be found in the archived file at the end of the article):
package.json
//check download section to see JS code { "name": "teams", "version": "1.0.0", "description": "teams", "main": "main.js", "scripts": { "test": "test", "tsc_amd_one": "tsc --module amd --outFile GameCompact.js Game.ts", "tsc_amd": "tsc --module amd Game.ts" }, "author": "dani", "license": "ISC", "dependencies": { "typescript": "^1.8.10" }, "devDependencies": {} }
7. Options
TypeScript compiler tsc supports a large list of options and parameters. In this article we only made use of a few of them in order to generate AMD RequireJS compatible modules. If you are interested in all the available options that the TypeScript compiler supports, please visit https://www.typescriptlang.org/docs/handbook/compiler-options.html.
8. Download
In the following link you can download a full working example covering the main components explained in this article: RequireJSTypeScriptExample
9. Links
The following links contain more information and references about the topics mentioned in this article:
- https://www.typescriptlang.org/docs/handbook/compiler-options.html
- https://www.typescriptlang.org/
- http://requirejs.org/
- https://www.webcodegeeks.com/javascript/requirejs/requirejs-tutorial-how-to-use-requirejs/
- https://nodejs.org/en/download/
Thanks for the article.
I am trying to introduces typescript in a javascript project that is using amd. Do you know of a way to use typescript with old amd modules?
http://stackoverflow.com/questions/42552364/using-amd-modules-with-typescript