Typescript
Javascript makes sense
Summary
- What is typing?
- Issues in ES6 that typing solves
- Typescript types
- Other typescript features
- How to integrate typescript: new project and migrations
What is typing?
“A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute.”
Pierce, Benjamin C. (2002). Types and Programming Languages. MIT Press
“In programming languages, a type system is a collection of rules that assign a property called type to various constructs a computer program consists of, such as variables, expressions, functions or modules.”
https://en.wikipedia.org/wiki/Type_system
What is typing?
Javascript already has it: remember typeof operand.
The latest ECMAScript standard defines seven data types (6 of them are primitives):
Boolean
Number
String
Symbol
Null
Undefined
Object
What is typing?
So, what is typescript?
Typescript is a typed superset of Javascript that compiles to plain Javascript.
It allows static and dynamic type checking, and also implements new ES features in advance.
Issues in ES6 that typing solves
Incorrect comparisons
var a = 1;
var b = '1';
console.log(a == b); // true
Issues in ES6 that typing solves
Typos
var a = { myProperty: 'hello world' };
console.log(a.myPoperty); // undefined
Issues in ES6 that typing solves
Passing incorrect values to methods
var a = '12-25-2016';
function printMonth(fullDate) {
console.log(fullDate.getMonth());
}
printMonth(a); // Uncaught TypeError: fullDate.getMonth is not a function
Issues in ES6 that typing solves
Even in tricky situations
var a = ['a', 'b', 'c'].push('d');
console.log(a.length); // undefined
Typescript types
A type is declared with the syntax variable: type
It can be done in every variable, even in function parameters or returns (this is specially useful!)
var a: number = 12;
var b: string;
function numberToString(num: number): string {
return num.toString();
}
b = numberToString(a);
Typescript comes with the native javascript methods typed, and we can integrate typings for known libraries.
Typescript types
Basic types
// Boolean
var a: boolean = false;
// Number
var b: number = 100;
// String
var c: string = 'something';
// Array
var d: string[] = ['array', 'of', 'strings'];
var e: Array<string> = ['two', 'ways', 'to', 'type'];
// Any
var f: any = 12;
f = f.toString();
f = [f];
Boolean
Number
String
Array
Any
Typescript types
Basic types
// Tuple
var a: [string, number];
a = ["hello", 10]; // OK
a = [10, "hello"]; // Error
// Enum
enum Month {January = 1, February = 2};
var b: Month = Month.January;
enum Gender {Male, Female, Other, Unknown};
var c: Gender = Gender.Male; // 0
// Void
function noReturn(): void {
console.log('Im returning nothing');
};
Tuple
Void
Enum
Typescript types
Basic types
// Never
function unreachableValue(): never {
throw new Error('Out of the function');
}
// Null
var a: null = null;
// Undefined
var b: undefined = undefined;
Never
Undefined
Null
Typescript types
Interfaces
interface IUser {
gender: Gender; // This is our custom enum!
name: string;
surname?: string; // Optional property. Use with care
birthDate: Date; // Classes work as a type
readonly mail: string; // We can declare read only properties
}
What is the point of all this if we can't declare our own "types"?
interface IManager extends IUser {
canDelete: boolean;
}
Interfaces can be extended. This way we inherit properties
Also, classes can implement interfaces. Too complex for this talk. Sorry!
Typescript types
Advanced types: how the hell do I...?
Type functions
function toNumber(value: number | string): number {
return typeof value === 'number' ? value : parseInt(value);
}
Manage a param that can have multiple types (union types)
function doSomething(param: string, callback: (num: number) => any) {
callback(parseInt(param));
}
doSomething('1', function (a: number) {}); // OK
doSomething('2', function (a: string) {}); // Error
Be careful with union types, they make the typing less reliable
Typescript types
Advanced types: how the hell do I...?
Check the instance of a value
type Gender = 'male' | 'female' | 'other' | 'unknown';
var userGender: Gender = 'female';
function getSectionIcon(section: 'main' | 'aboutUs' | 'blog') {
return 'assets/icons/' + section.toLowerCase() + '.gif';
}
getSectionIcon('aboutUs'); // 'assets/icons/aboutus.gif'
getSectionIcon('mainSection'); // Error argument of type 'mainSection'...
Restrict a string to some values (string literal types)
function addContent(whoIsAsking: IUser | IManager): void {
if (whoIsAsking instanceof IUser) {
throw new Error('You shall not pass!');
} else {
myApi.addContent();
}
}
Typescript types
Type inference, compatibility and assertion
Declaring types for everything can be a pain in the ass but luckily, typescript can guess types. That's call inference.
Even though it's a cool feature, if we are not careful it could led to inference "any" for everything. Don't be too lazy!
var a = [3]; // a is treated as number[]
a.push('2'); // Error
function transform(variable) {
return variable.toString();
}
var b = transform(3); // b is treated as any
Typescript types
Type inference, compatibility and assertion
Two different types or interfaces can be compatible.
interface Named {
name: string;
}
var x: Named;
var y = { name: "Alice", location: "Seattle" };
x = y; // OK, because y has the only property that Named needs
enum MyValues { 'first', 'second', 'third' };
var a: MyValues;
var b: number = 0;
a = b; // OK, number is compatible with any enum
var c: number = 4;
a = 4; // Also OK, ANY number is compatible with ANY enum
Typescript types
Type inference, compatibility and assertion
Sometimes, we don't want to add an interface for everything, or we just know more than Typescript. Here is where assertion comes in handy.
interface IFish {
swim: () => void
}
interface IBird {
fly: () => void
}
function isFish(pet: IFish | IBird): boolean {
return (<IFish>pet).swim !== undefined;
}
Other typescript features
With Typescript, we have access to oncoming ES features.
And, since it's later compiled to the javascript version of our choice, we don't need to care about browser compatibility.
// Typescript
const ROOT: string = 'localhost:8080/';
let filename: string = 'somefile.jpg';
let fullpath = `${ROOT}folder/${filename}`;
// ES5
var ROOT = 'localhost:8080/';
var filename = 'somefile.jpg';
var fullpath = ROOT + "folder/" + filename;
Early access to new ES features
Other typescript features
// Typescript
let base = [1, 2, 3];
let extended = [...base, 4, 5];
// ES5
var base = [1, 2, 3];
var extended = base.concat([4, 5]);
// Typescript
function myFunction([x, y]: number[]) {
console.log(x, y);
}
// ES5
function myFunction(_a) {
var x = _a[0], y = _a[1];
console.log(x, y);
}
Early access to new ES features
Other typescript features
Early access to new ES features
// Typescript
[1, 2, 3, 4].filter((num: number) => num < 2);
// ES5
[1, 2, 3, 4].filter(function (num) { return num < 2; });
// Typescript
for (let val of ['a', 'b', 'c']) {
console.log(val);
}
// ES5
for (var _i = 0, _a = ['a', 'b', 'c']; _i < _a.length; _i++) {
var val = _a[_i];
console.log(val);
}
How to integrate typescript
Initial configuration
First, add the main dependancies: typescript, tslint, and any desired 3rd party type definitions
npm install --save-dev typescript tslint
npm install --save-dev @types/lodash
More info here:
https://github.com/DefinitelyTyped/DefinitelyTyped
https://github.com/DefinitelyTyped/DefinitelyTyped#other-methods
How to integrate typescript
Initial configuration
Add a tsconfig.json file to the root of your project
{
"compilerOptions": {
"module": "system",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true // This is useful for debugging
},
"include": [
"src/**/*" // Look for .ts files here and compile them
],
"exclude": [
"node_modules", // Except for these
"**/*.spec.ts"
]
}
https://www.typescriptlang.org/docs/handbook/compiler-options.html
How to integrate typescript
Initial configuration
Tsling works like jshint (you should now this one) but for .ts files. Create a tslint.json file at the root of the project and configure it to your needs.
Full list of rules:
https://palantir.github.io/tslint/rules/
Even custom designed rules:
https://palantir.github.io/tslint/usage/custom-rules/
How to integrate typescript
Gulp automation
Typescript sourcemap options are not supported by gulp at this moment, so we'll need a specific package.
You may want to add another packages like gulp-watch, servers, etc, and integrate the compilation in that flow.
npm install --save-dev gulp gulp-typescript gulp-sourcemaps gulp-tslint
gulp.task('ts-lint', function () {
return gulp.src(‘src/**/*.ts’).pipe(tslint()).pipe(tslint.report());
});
On the other hand, gulp-tslint automatically locates and uses tslint.json so this part is simple:
How to integrate typescript
Gulp automation
And last, compilation:
var tsProject = typescript.createProject('tsconfig.json');
gulp.task('compile-ts', function () {
var tsResult = gulp.src(‘src/**/*.ts’)
.pipe(sourcemaps.init())
.pipe(typescript(tsProject));
return tsResult.js
.pipe(sourcemaps.write())
.pipe(gulp.dest(‘dist’));
});
An example:
http://blog.scottlogic.com/2015/12/24/creating-an-angular-2-build.html
Typescript: Javascript makes sense - original
By Paqui Calabria
Typescript: Javascript makes sense - original
Introduction to typescript, its advantages, main features and how to use it in your projects.
- 1,191