the flavor of typescript
TRANSCRIPT
The flavor of TypeScripta hands-on guide
September 2016
I'm Dmitry Sheiko, a web developer, blogger, open source contributor.
@sheikohttp://dsheiko.com
TypeScript is a superset of JavaScript
that enables language features such as…
static typing, interfaces,
abstract classes, member visibility
and more
TypeScript compiles to JavaScript
(ES5 or higher)
Agitated? Let’s give it a start
npm install typescript -gInstall typescript
{ "compilerOptions": {
"target": "ES5", "module": "commonjs",
"moduleResolution": "node"outDir": "build/"
}, "files": [ "./app.ts" ]}
Create tsconfig.json
function append( line: string ): string { return "suffix" + line;}
var res: string = append( "a string" );
Write test module app.ts
tscCompile typescript
function append(line) { return "suffix" + line;}var res = append("a string");
Observe the generated build/app.js
TypeScript has simply removed the typing
However if in our source we try to give a wrong type the IDE warns us:
TypeScript compiler also warns us:tsc
src/app.ts(5,27): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
How does TypeScript deal with modules?
import { foo } from "./foo";console.log( foo );
TypeScript accepts ES6 module syntax (https://www.typescriptlang.org/docs/handbook/modules.html)app.ts
export var foo: string = "a string";foo.ts
"use strict";var foo_1 = require("./foo");console.log(foo_1.foo);
According to our tsconfig.json configuration TypeScript compiles them in CommonJS modules:app.ts
"use strict";exports.foo = "a string";
foo.ts
We can bundle TypeScript-generated
modules with Browserfy
(http://browserify.org/)
Alternatively we can load them
asynchronously with e.g. SystemJS
(https://github.com/systemjs/systemjs)
With TypeScript one may write in latest JavaScript syntax (ES2015/2016).
TypeScript can compile to JavaScript suitable for old
browsers.
Variables and scoping
if ( true ) { let foo = "foo";}console.log( foo ); // undefined
Block scope
const foo = "foo";foo = "bar"; // ERROR
Constants
Template literal
let foo = `linelineline`;
Multi-line strings
let foo = "foo", bar = "bar", str = ` ${foo}, ${bar}`;console.log( str ); // foo, bar
Template literal
Arrow functions
this.foo = 1;let res = [ 1, 2, 3 ].map(( n ) => { return this.foo + n;});console.log( res ); // 2, 3, 4
Shorter syntax where the callback keeps outer context
this.foo = 1;let res = [ 1, 2, 3 ].map( n => this.foo + n );console.log( res ); // 2, 3, 4
Can be even shorter
Classes
class Foo { bar() { return "bar"; } static baz() { return "baz"; }}
console.log( Foo.baz() );let foo = new Foo();console.log( foo.bar() );
Syntactic sugar over prototypes
class Foo { bar() { return "bar"; }}class Baz extends Foo {}let baz = new Baz();console.log( baz.bar() );
Class-based inheritance
class Foo { constructor( arg ) { this.arg = arg; }}class Bar extends Foo { constructor( arg ) { super( arg ); }}let bar = new Bar( "arg" );console.log( bar.arg );
Constructor function
Leaner Object Literals
let baz = "baz";let obj = { foo: "foo", bar() { return "bar"; }, baz}console.log( obj ); // Object { foo="foo", baz="baz", bar=function()}
ES6 method definition and default value
Arguments
function foo( start = 0, end = 1 ) { console.log( start, end );}
Named parameters
function foo({ start = 0, end = 1 } = {}) { console.log( start, end );}
Optional parameters
function log( msg, ...args ) { console.log( msg, args[ 0 ], "..." );}log( "passing nums", 1, 2, 3 ); // passing nums 1...
Rest parameters
function save( foo, bar, baz ) { console.log( foo, bar, baz );}let csv = "foo,bar,baz".split( "," );save( ...csv ); // foo bar baz
Spread operator
Collections
const map = new Map();map.set( "aKey", "a value" );map.get( "aKey" ); // "a value" valuemap.size; // 1
// Key can be an objectmap.set( window, "a value" );
map.forEach(( value, key ) => { //..});map.has( "aKey" ); // truemap.delete( "aKey" );map.clear();
Maps
const set = new Set([ 1, 2, 3, 4 ]);
set.add( 5 );set.has( 5 ); // trueset.size; // 5set.delete( 5 );set.size; // 4
set.forEach( console.log ); // 1, 2, 3, 4set.clear();set.size; // 0
Sets
Symbols
const ERR_CODE = { TYPE_ERROR: Symbol(), SYNTAX_ERROR: Symbol()}
console.log( ERR_CODE.TYPE_ERROR === ERR_CODE.TYPE_ERROR ); // true
A symbol is a unique and immutable data type
Destructuring
let foo, bar, baz;[foo, bar, baz] = "foo,bar,baz".split( "," );
Array destructuring
let { foo, bar } = obj;// foo = "foo", bar = "bar"
Object destructuring
let obj = { foo: "foo", bar: "bar" };let { foo: f, bar: b} = obj; // f = "foo", b = "bar"
Aliasing during destructuring
let el = document.getElementById( "#foo" );const { querySelector, querySelectorAll } = el;querySelector( ".class" );
Extracting shorteners
Decorators
Decorators allow to annotate or modify classes and class
members
{ "compilerOptions": {
… "emitDecoratorMetadata": true, "experimentalDecorators": true }, …}
Add to tsconfig.json
function Mixin( data ) { return function( target ){ Object.assign( target.prototype, data ); };}
@Mixin({ bar: "bar"})class Foo {}let foo = new Foo();console.log( foo.bar );
Modifying the prototype
function Readonly( target, key, descriptor ) { descriptor.writable = false; return descriptor;}
class Foo{ @Readonly bar(){ }}let foo = new Foo();foo.bar ="bar"; // ERROR
Annotating a member
Extras
function test(){ let arr = Array.from( arguments ); Array.isArray( arr ); // true arr.includes( 2 ); // true arr.find( n => n === 2 ); // 2}test( 1, 2, 3 );
Array extras
let foo = { foo: "foo" };Object.assign( foo, { bar: "bar" } );foo; // { foo: "foo", bar: "bar" }
Object.assign
TypeScript enhancement
Interfaces
interface Rectangle { width: number; height: number; calcArea(): number;}
class Square implements Rectangle { width: number; height: number; calcArea() { this.width * this.height; }}
Interface to implement
interface DataMap { [key: string]: any;}
function stringify( data: DataMap ){ return JSON.stringify( data );}
stringify({ foo: [ 1,2 ] });
Interface in type annotation
interface DataMap<Val> { [key: string]: Val;}
function stringify( data: DataMap<string> ){ return JSON.stringify( data );}
stringify({ foo: "foo" });
Interface with a generic
Abstract classes and member visibility
abstract class Foo { protected bar(){}}
class Bar extends Foo { private secret: string = "secret"; public quiz(){ return this.bar(); }}
Abstract, public, private, and protected modifiers
Parameter properties
class Foo { public constructor( public arg: string = "default"){ }}let foo = new Foo();console.log( foo.arg ); // default
Parameter properties let you create and initialize a member in one place
class Foo { private bar: string = "bar"; baz: number[] = [ 1, 2 ]; static quiz: boolean = true;}
We cannot declare properties in ES6, but we can with TypeScript
Casting types
function geInput(): HTMLInputElement { let el = <HTMLInputElement> document.querySelector( "input" );}
document.querySelector returns always abstract Element type regardless of the selector. If you expect a concrete implementation of Element (e.g. HTMLInputElement), you can cast it.
Union type
function validate( spec: string | string[] ): boolean { if ( !Array.isArray( spec ) ) { spec = <string[]>Array.of( spec ); } return spec.every( isSpecValid );}
Here parameter spec is allowed to be either a string or an array of strings
We can use in TypeScript existing JavaScript libraries
What about external library interfaces?
npm install typings --globalInstall Typings
typings search --name backbone
Search for available type definitions
typings install dt~backbone --global --save
Install definitions
{ …, "files": [ "./typings/index.d.ts", … ]}
Add typings index to tsconfig.json
class View extends Backbone.View { events: { "click button": "onClick" } onClick( e: Event ) { e.preventDefault(); }}
Now we can use a library, e.g. BackboneJS
Thank you!