Typescript is just Javascript only better. Think of it as a preview of what Javascript might be like in many years when we can consider the current crop of browsers as out-of-date.

History

TypeScript was developed by Microsoft as a way to write in the future versions of JavaScript before those versions were supported in browsers. In fact, it guarantees that the current crop of browsers can be used for the foreseeable future as long as TypeScript code is transpiled to older versions of JavaScript.

Concepts

Typescript is JavaScript with gradual static typing. This means that types may be specified in code for any particular variable, but the language will attempt to reconcile anything that is not declared at compile time.

Since TypeScript complies down to JavaScript, we can observe that the types are only included for sanity’s sake. Which would you prefer? To be told about a problem early, or to find out about a problem after you can’t change it and it has been shown to the world? This is the idea behind static typing in TypeScript. Verify your programs are as syntactically correct as can be verified, and produce better code.

Features

Type declarations of:

  • String

  • Number

  • Boolean

  • Array

  • Null

  • Any

  • Void

  • Enum

  • AND CLASSES!

Classes come to JavaScript as “first-class” citizens. We can create our own types!

Interfaces come along with classes!

Inheritance comes along with classes!

Modules allow us to separate code over multiple files. No more module.exports! See Namespaces and Modules · TypeScript

New habits

Stop using var and start using let

While var still works, let allows you to use the newer block-scoping rules, which will protect you from writing bad code.

Start using const for variables that will never change

These are immutable values and they will protect you from accidentally altering a variable that you intend to never change.

Use type annonations for every variable/argument/etc

Type annotations are required by default with the TypeScript configuration we will use. But be sure to not forget. function add(x, y) is not as complete or as good as function add(x: Number, y: Number)

Use the fat arrow as much as possible

Writing function(req, res) {} as a callback does not protect your this variable. Instead, use the fat arrow, (req, res) ⇒ { …​ } and you will have no need to ever worry about this again.

No more module.exports

We now will use export before any name we wish to expose to the outside world. See the examples below.

The process

  1. Set up a project

  2. Set up a project: npm init

  3. Install the compiler: npm install -g typescript

  4. Create tsconfig.json

    1. Run tsc --init — not recommended! Grab a sample from below for today’s purposes.

    2. See tsconfig.json · TypeScript

  5. Write TypeScript into .ts files

  6. Invoke the tsc “compiler” (transpiler) to convert that code into runnable JavaScript

  7. Load the JS into whatever environment you are executing, be that node or a browser.

Linters

GitHub - palantir/tslint: An extensible linter for the TypeScript language . npm install -g tslint . tslint --init in your project directory . Edit tslint.json to match the code style you wish to use. .. See Configuring TSLint

Build tools

We’ll be using Angular for most of our needs, but there are other build tools too.

Example Project

Project setup

Run the following in a fresh directory:

  • mkdir src dist

  • npm init -y

  • npm install -g gulp-cli

  • npm install --save-dev typescript gulp gulp-typescript

And set up the following files:

First, package.json as with any package.

package.json (generated with npm init -y)
{
  "name": "ts",
  "version": "1.0.0",
  "description": "",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp": "^3.9.1",
    "gulp-typescript": "^5.0.0-alpha.3",
    "typescript": "^3.1.3"
  }
}

The tsconfig.json file tells typescript what to compile and how. There are many details that can be added to this file, but the following is a fine quickstart.

tsconfig.json
{
	"files": [
		"src/hello.ts"
	],
	"compilerOptions": {
		"noImplicitAny": true,
		"target": "es5"
	}
}

The gulpfile.js tells the Gulp build tool how to build this project. Adding TypeScript can be complicated, especially when it becomes time to handle module imports from multiple files or use a tool to pack everything into one minified file for a web browser. Gulp makes this slightly more sane.

gulpfile.js
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");

gulp.task("default", function () {
    return tsProject.src()
        .pipe(tsProject())
        .js.pipe(gulp.dest("dist"));
});

Project files

Since we told TypeScript to comile any .ts file in src, we can write whatever we want in the src directory and it will end up in the dist directory as a .js file.

src/hello.ts
function hello(compiler: string) { (1)
    console.log(`Hello from ${compiler}`); (2)
}
hello("TypeScript");
1 Note that compiler may not be anything but a string since it is annotated.
2 This is a format string. Use the back-tick and ${varName} to insert variables into strings.

Let’s break that into two files:

src/greet.ts
export function sayHello(name: string) { (1)
    return `Hello from ${name}`;
}
1 We must export any function we wish to be accessible from outside of this file.
src/main.ts
import { sayHello } from "./greet"; (1)

console.log(sayHello("TypeScript"));
1 New import! No more require! You may import specific things exported from another file as a list inside of the {}

Sending code to the browser

We need to do a little bit of extra work to send code to the browser.

First, install some tools: npm install --save-dev browserify tsify vinyl-source-stream

browserify and tsify are tools that "bundle" up your module code so that the browser might understand it. vinyl is a tool that lets gulp understand that output.

Write a .html webpage to load:

src/index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello World!</title>
    </head>
    <body>
        <p id="greeting">Loading ...</p>
        <script src="bundle.js"></script>
    </body>
</html>

Change main.ts to update the page instead of log:

src/main.ts
import { sayHello } from "./greet";

function showHello(divName: string, name: string) {
    const elt = document.getElementById(divName);
    elt.innerText = sayHello(name);
}

showHello("greeting", "TypeScript");

And, unfortunately the gulp file needs more magic:

gulpfile.js
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
var paths = {
    pages: ['src/*.html']
};

gulp.task("copy-html", function () {
    return gulp.src(paths.pages)
        .pipe(gulp.dest("dist"));
});

gulp.task("default", ["copy-html"], function () {
    return browserify({
        basedir: '.',
        debug: true,
        entries: ['src/main.ts'],
        cache: {},
        packageCache: {}
    })
    .plugin(tsify)
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest("dist"));
});

An Express server in TS

First, install type definitions for Express: npm install --save @types/express

src/main.ts
import * as express from "express"; (1)
import { routes } from "./routes"; (2)

class ExpressServer {
	private port: Number;
	private app: express.Express; (3)

	constructor(port: Number = 8080) {
		this.port = port;
		this.app = express();
		this.app.use('/v1', routes);
	}

	start() {
		this.app.listen(this.port, () => {
			console.log(`Listening on ${this.port}`);
		});
	}
};

let es = new ExpressServer(8080);
es.start();
1 Note that the type definition gave us this as the import. You can look at node_modules/@types/express/index.d.ts to see what’s in this type definition that we installed.
2 We’ll write a routes file for our router middleware. This is just the new syntax for importing it.
3 Private variables on the class. No need to export our server itself. We could provide methods to add middleware or perhaps could have just extended the express.Express class instead of enclosing it.

The routes file is (currently) about the same as before. We could also add classing here and do some fancy things.

routes.ts
import * as express from "express";

export let routes = express.Router();

routes.get('/hello', (req, res) => {
	res.send("Hello World!");
});

routes.get('/hello/:name', (req, res) => {
	res.send(`Hello ${req.params.name}!`);
});

GOOD NEWS

There are other build tools out there. This example came from Gulp · TypeScript

Modern Angular takes care of much of this project nastyness. We’ll see its build tools in a future episode.