Typescript Language Primer
An introduction to a Javascript alternative that allows you to code with decorators/annotations, classes, interfaces, private properties, and typing compliance.
Join the DZone community and get the full member experience.
Join For FreeTypeScript is an open source typed superset of JavaScript which compiles to plain JavaScript. Many people have considered JavaScript’s loose typing as a problem, but now Typescript offers a solution to that. Specifically, Typescript allows you to code with decorators/annotations, classes, interfaces, private properties and typing compliance.
We also might say that TypeScript is ES6 with some extra options.
What Does TypeScript do?
Typescript formalizes JavaScript’s types compiling and even offers auto-completion with some IDEs, which of course makes our lives as developers easier. If you do not place much value on auto-completion, Typescipt also provides other features which may interest you, for example syntax validation and types checking. There is now a real trend in the evolution of web applications toward the development of Large SPAs (Single Page Applications). In this context, JS is being pushed hard and TS is one of the tools that has been developed to enable strict typing validation during compilation, thereby keeping consistency within your code. TS detects some syntax errors that would normally only be found during testing, such as a function that is ready to handle an integer parameter and eventually is called with one of type string. It is worth noting that Typescripts’s syntax is very similar to Java, Csharp and C++ rather than ruby or python.
Developers typically install TypeScript using the npm (node package manager). When doing this you need to create a tsconfig.json file which will allow you to define the JavaScript target, module type, module resolution type and so on. Some options that I consider important are: watch, noImplicitAny and removeComments; set them respectively as true, false, false.
Watch keeps observing your TS files and automatically compiles when there is any change; setting the noImplicitAny flag to false means that the compiler will not supply an error if you do not explicitly type variables rather it just assumes they have type ‘any’; removeComments will help you to map the differences between TS code and JS. Though, comments might be removed after processing JS files in minification.
What are the Differences Between TypeScript and Plain JavaScript?
In my opinion the key points worth highlighting about TS are (note: items with 1.8 is only available from it):
- Learning TS does not require learning a new language, actually, it is being aligned to the new EcmaScript 2015 language specification;
- Interface: developers can define their types as interfaces and add them to parameters and returns for methods and functions thereby increasing the readability of the code;
// Declaring a simple interface that has 2 public properties x and y
interface Point {
x: Number;
y: Number;
}
function getGreaterAxisValue(point: Point) {
return (point.x > point.y) ? point.x : point.y;
}
getGreaterAxisValue({ x: 10, y: 30 }); // return 30
getGreaterAxisValue({ x: 20, y: 3 }); // return 20
// Declaring a simple interface that has 2 public properties x and y
interface Point {
x: Number;
y: Number;
}
class Point2D implements Point {
x: Number;
y: Number;
constructor(x: Number, y: Number) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point2D {
z: Number;
constructor(x: Number, y: Number, z: Number) {
super(x, y);
this.z = z;
}
}
class MyCustomWindow {
constructor() {
window.onmousedown = function(e) {
console.log(this.toString())
};
window.onmousemove = (e) => {
console.log(this.toString())
};
}
toString() {
return “It’s me! Marioooooo!”;
}
}
let w = new MyCustomWindow();
/*
Now, every time when I click, I will get the toString value from window, where as when I move, I will get from MyCustomWindow.
*/
function logme(name: String, age) {
console.log(“I am ${name} and I am ${age} years old”);
}
function logmeAgain(name: String, age: Numm) {
console.log(“I am ${name} and I am ${age} years old”);
}
// In both execution, I will get the same result
// >> I am Danilo and I am 32 years old
logme(“Danilo”, 32);
logme(“Danilo”, “32”);
logmeAgain (“Danilo”, 32); // >> I am Danilo and I am 32 years old
logmeAgain (“Danilo”, “32”); // Compilation error: argument type mismatch
Being able to decompose an object/array into variables is very helpful to get develop clean code: think more, code less.
let calc = {
operation: “sum”,
operator1: 23,
operator2: 41
}, ops = [23, 41];
let {operator1, operator2, operation} = calc;
console.log(operator1, operator2, operation); // >> 23 41 sum
function sum({operator1, operator2 }) {
return operator1 + operator2;
}
sum(calc);
console.log(sum(calc)); // >> 64
console.log(sum(…ops)); // >> 64
Although you can declare a property as private, it does not work as a private property at runtime. As I already said, TS is just a superset of JS which runs and validates the code at compilation time. So, be careful! It is really important to know what the compiler does with your code.
The TS compilation process is able to be customized enabling even more strict validation as you can see below.
- Unreachable code (off by default, enable through –allowUnreachableCode);
- Unused labels (off by default, enable through –noImplicitReturns);
- Implicit returns (off by default, enable through –noFallthroughCasesInSwitch);
You might use destructuring and defaults to define props easily. See the following code:
const Hello = ({greeting = ‘Hello’}) => <div>{greeting}</div>;
let example = <Hello name=’TypeScript 1.8’ />;
We can create not only classes, but also compositions.For example, let’s say that you’re using a type but need to add some extra methods…
// FlexNumber.ts
export class FlexNumber extends Number {
constructor(val) {
super(val);
}
}
// FlexNumber.add.ts
import {FlexNumber} from ‘./FlexNumber’
declare module ‘./FlexNumber’ {
interface FlexNumber {
add(val: Number): FlexNumber;
}
}
FlexNumber.prototype.add = function(val: Number) {
return new FlexNumber(this + val);
};
// main.ts
import {FlexNumber} from ‘./FlexNumber’
import ‘./FlexNumber.add’
console.log(new FlexNumber(3).add(4)); // >> 7
String literal validation is more like enums. It is easy to understand that you can define possible values for a property as shown in the code below.
interface TeamColours {
colour: “red” | “blue” | “white”;
}
class Team {
constructor(colours: TeamColours){
this.colours = colours;
}
}
new Team({ colour: “Black” }) // Error: Type ‘”Black”’ is not assignable to type ‘“red” | “blue” | “white”’
new Team({ colour: “blue” }); // Works, colour is allowed
Previously, variables declared within loop statements using let or const operator weren’t allowed be accessed inside closures.
let list = [];
for (let i = 0; i < 5; i++) {
list.push(() => i);
}
list.forEach(f => console.log(f()));
/**** results
>> 0
>> 1
>> 2
>> 3
>> 4
***********/
All modules are parsed in strict mode. Previously, they were compiled with strict mode just for ES6 target. This implies that the code used to silently fail at runtime, such as assigning to NaN. In TS code this will now loudly fail.
During the compilation you can specify the factory using the parameter “—reactNamespace <your factory name here>”. Knowing so, we can run some examples.
// main.ts
import {jsxFactory} from “jsxFactory”
let div = <div>Hello world from your first component.</div>;
Compiling: tsc –jsx react –reactNamespace jsxFactory –m commons
Results in:
“use strict”;
var jsxFactory_1 = require(“jsxFactory”);
var div = jsxFactory_1. jsxFactory.createElement(“div”, null, “Hello world from your first component.”);
There are many other features beyond the ones that I have discussed in this post. This subset has function and code style guide at a high level. As you can see TS has many features that ensure consistency and quality of code.
Should I Be Careful With TypeScript?
There are some aspects of TS which you need to consider:
- Be careful with the extra features, otherwise you will end up depending on the TS;
- There is no annotation/decorator for ES 2015: it requires a polyfill to keep consistent;
- Private properties are assigned to object context “this”, it means that is not private at all. Everybody knows that once you have functions or values assigned to the object context “this”, it becomes public. But the superset validation is performed at compile time, then, if you try to access a “private” property, it will be considered a violation and it won’t compile your TS code;
- Keep in mind that Typescript is an extension to JavaScript to force variable typing, but what makes JS powerful is that it is a dynamically typed language and so you need to be careful to not overuse Typescript.
- So, in which cases is loose typing important? JavaScript does not have polymorphism.
Think about providing a promise for a map based on an array of elements and that you could also receive a promise as input.
// Given a list of colours
let elements = [{ id:1, name: 'Blue’, value: ‘#0000FF’}, { id:1, name: 'White’, value: ‘#FFFFFF’}, { id:1, name: 'Red’, value: ‘#FF0000’}];
// Or a promise for a list of colours
let colourPromise = new ColourService().getAll(); // Assume it returns a promise that resolves an array of colours;
function isPromise(obj) {
… // Check if is a promise
}
function getMap(colours) {
if (isPromise(colours) {
return colours.then( (data) => getMap(data));
} else {
let map = {}, promise = new Promise(() => {
colours.forEach((colour) => { map[colour.value] = colour.name; });
return map;
});
return promise;
}
}
Well, knowing that we do not have polymorphism and getMap has to provide the same result for both cases, you can see that loose typing is very powerful if used when required.
Should I Use TypeScript?
The answer is pretty simple. As with any other language, you need to understand your product’s domain and then find the language which suits it best. If you are thinking about starting a new web project you will most likely end up using JavaScript and so I would recommend using Babel as this will provide future proofing if you wish to remove the compiler when browsers are capable of natively interpreting ES2015. In the meantime you can get some of these advantages today by using TypeScript rather than using simple ES2015.
References
Anders Hejlsberg: Introducing TypeScript
https://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript
Published at DZone with permission of Justin Buchanan, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments