TypeScript & Observables
Agenda
- What is TypeScript
- Why use Typescript?
- TypeScript Concepts
- Observables
- Q&A
What is it?
TypeScript is a free and open source programming language developed and maintained by Microsoft. (I know... I know...) It is a strict superset of JavaScript, and adds optional static typing and class-based object-oriented programming to the language.
TypeScript is a superset of JavaScript
Not the first attempt at "fixing" JavaScript.
Over 250 languages compile down to JavaScript
Compile-to-JavaScript frameworks can generally be categorized into two camps
- Those that build on top of JavaScript
- Those that abandon JavaScript completely.
Most frameworks fall into the latter camp
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
some-javascript.js
some-typescript.ts
Most pre-existing JavaScript
is already valid TypeScript
function numberCruncher (numA, numB){
return numA + numB;
}
JavaScript Issues
var result = numberCruncher(5, 5);
console.log(result);
>> 10
result = numberCruncher(5, true);
console.log(result);
>> 6
result = numberCruncher(5, 'js4lyfe');
console.log(result);
>> "5js4lyfe"
result = numberCruncher(5, {param: true});
console.log(result);
>> "5[object Object]"
function myTypedFunction(paramName : dataType) : returnType {
// Regular junk here
}
Typing with TypeScript
var varName : string = 'Woot!';
Type a variable:
Type a function:
function trimLength(inputVal : string) : number {
return inputVal.trim().length;
}
Types
- Boolean
- Number
- String
- Array
- Tuple
- Enum
- Any
- Void
- *Union
Boolean
let flag: Boolean = false;
flag = 2; //Error: Type "Number" is not assignable to type "Boolean"
Number
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
decimal = "hello" //Error!
String
let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`
Array
let numeric: Array<number> = [1, 2, 3];
let strings: Array<string> = [1, 2, 3];
let shapes = Array<Shape> = [new Shape(), new Shape(), new Shape()]
Tuple
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
Tuple types allow you to express an array where the type of a fixed number of elements is known, but need not be the same.
Enum
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
Any
Restores basic JavaScript dynamic typing behavior
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
Void
function initSomething() : void {
doSomeStuff();
}
var pointless = initSomething(); // 🍋Compiler Error
A function that returns nothing.
NOTE: Declaring variables of type void is not useful because you can only assign undefined or null to them:
Union
let foo : string | boolean;
foo = true;
foo = "true";
foo = 1; //Error!
Classes
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() : String {
return "Hello, " + this.greeting;
}
}
let greeter : Greeter = new Greeter("world");
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
Inheritence
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
console.log("Galloping...");
super.move(distanceInMeters);
}
}
let tom: Animal = new Horse("Tommy the Palomino");
tom.move(34);
Public
Public is the default accessor.
//These are equivalent
class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
Private
Cannot be used outside the class.
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
new Animal("Cat").name; // Error: 'name' is private;
Protected
Protected acts much like the private modifier with the exception that members declared protected can also be accessed by instances of deriving classes
class Person {
protected name: string;
constructor(name: string) { this.name = name; }
}
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // error
Static
class Grid {
static origin = {x: 0, y: 0};
calculateDistanceFromOrigin(point: {x: number; y: number;}) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor (public scale: number) { }
}
let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
Abstract Classes
abstract class Department {
constructor(public name: string) {}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // must be implemented in derived classes
}
class AccountingDepartment extends Department {
constructor() {
super('Accounting and Auditing'); // constructors in derived classes must call super()
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type
interface Shape {
color: string;
}
Interfaces
Static compile-time analysis for enforcing "Duck Typing"
class Square implements Shape {
constructor(public color: string){}
}
let s = new Square("blue");
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
Interfaces (2)
interface Shape {
color: string;
}
Extending Interfaces
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
interface GridDefinition {
origin : { x: number; y: number; };
calculateDistanceFromOrigin( point: { x: number; y: number; })
}
//ERROR!
class Grid implements GridDefinition{
static origin = {x: 0, y: 0}; //The interface won't see static members
calculateDistanceFromOrigin(point: {x: number; y: number;}) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor (public scale: number) { }
}
Interface with Static Properties
Generics
function identity(arg: number): number {
return arg;
}
function identity(arg: any): any {
return arg;
}
function identity<T>(arg: T): T {
return arg;
}
class Collection<T> {
private _items = [];
public getItems() { return this._items; }
public count() { return this._items.length; }
public add(item: T) { this._items.push(item); }
}
Generic Classes
let numberCollection = new Collection<number>();
numberCollection.add(1);
numberCollection.add(2);
console.log(numberCollection.getItems());
//[1, 2]
let stringCollection = new Collection<string>();
stringCollection.add("Foo");
stringCollection.add("Bar");
stringCollection.add("Baz");
console.log(stringCollection.getItems());
// ["Foo", "Bar", "Baz"]
function assign<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
assign(x, { b: 10, d: 20 }); // { a : 1, b: 10, c: 3, d: 20}
assign(x, { e: 0 }); // Error
Type parameters as constraints
F-Bounded Polymorphism
Namespaces
namespace Utility {
export function log(msg) {
console.log(msg);
}
export function error(msg) {
console.error(msg);
}
}
Utility.log("Call me");
Utility.error("maybe!");
TypeScript!
- Official Website: typescriptlang.org
- Build Tools
- Gulp: gulp-typescript
- Grunt: grunt-typescript
- Webpack
- Editor Support
- Atom: atom-typescript
- Sublime: Better TypeScript
- IntelliJ Idea: Native support
1.8 is out now!
Observables
A generalized mechanism for push-based notification in JavaScript.
Demo
Questions?
TypeScript
By nicksterling
TypeScript
- 1,814