TypeScript

WHY TYPEs?

  • Contracts between things
  • Detect problems earlier
  • You're doing it anyway
  • You can just enter JSX code in it
  • All the cool kids are doing it
  • You already write TypeScript
  • Probably faster

BUT I DON'T LIKE TYPES

BUT I DON'T LIKE TYPES


+('' + +'0xff'+ +0)+1 +[]+ +[] + {} + (0.1+0.2)

SAME OLD types

const boolyMcBoolBool: boolean = true;
const numyMcNumNum: number = 1337;
const stringyMcStrStr: string = "☃";

let anyMcAnAn: any = {};
anyMcAnAn = 1; // That's "fine".

Meet the NEW type

enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}

let playerDirection: Direction = Direction.Up;

null and undefined are different now

let s = "foo";
s = null; // error, 'null' is not assignable to 'string'
let sn: string | null = "bar";
sn = null; // ok

sn = undefined; // not assignable to 'string | null'

Remix the types


// These do the same thing
let nums1: number[] = [1, 2, 3];
let nums2: Array<number> = [1, 2, 3];

                     +-------+
                     | +-+   |
                     | ^ |   |
                char *str[10];
                 ^   ^   |   |
                 |   +---+   |
                 +-----------+

please Contain your nostalgia for C/c++

class Person {
    constructor(public name: string) { }
}

interface Loggable {
    log(): void;
}

class ConsoleLogger implements Loggable {
    log() {
        // Returning something would break my interface
    }
}

this UNION THING is cool

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // I can only return a Fish or a Bird
}

Yes, you can intersect types also

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

var jim = extend(new Person("Jim"), new ConsoleLogger());

I forgot about the

type type

type StringyNumber = string | number;

let example: StringyNumber = "hello"
example = 1 // This is actually fine.

Call the guards

Call the guards

if (pet.swim) {
    pet.swim();
}

// or

if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
}

Call the guards

function stuff(param1: string, p2: string | number) {
    // I accept calls like:
    // stuff("", "")
    // stuff("", 2)
}

OVERLOAD the guards

interface Cloner {
    clone(animal: Dog): Dog;
    clone(animal: Cat): Cat;
    clone(animal: Sheep): Sheep;
    clone(animal: Animal): Animal;
}

Also this thing

function isNumber(x: any): x is number {
    return typeof x === "number";
}

/* 
// Compiler checks for guard violations, 
// and removes them when building JS:

function isNumber(x) {
    return typeof x === "number";
}
*/

Decorate

get fancy

Decorate everything

  • Classes
  • Methods
  • Parameters
  • Properties

Classes

function MyClassDecorator(value: string) {
  return function (target: Function) {
      console.log(“MyClassDecorator”, value, target);
  }
}

@MyClassDecorator(“my metadata”)
class MyClass { }

var myClass = new MyClass();

Methods

function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
    descriptor.value = function(...args: any[]) {
        console.log("The method args are: " + JSON.stringify(args));
        return result;
    };
    return descriptor;
}

class MyClass {
    @log
    myMethod(arg: string) { 
        return "Message -- " + arg;
    }
}

Property

function PropertyDecorator(
    target: Object, // The prototype of the class
    propertyKey: string | symbol // The name of the property
    ) {
    console.log("PropertyDecorator called on: ", target, propertyKey);
}

class PropertyDecoratorExample {
    @PropertyDecorator
    name: string;
}

Parameters

class MyClass {
    myMethod(@logParam myParameter: string) {}
}

function logParam(target: any, propertyKey: string | symbol, parameterIndex: number) {
	console.log(target);         // MyClass prototype
	console.log(propertyKey);    // "myMethod"
	console.log(parameterIndex); // 0
}

"Typings"

And other awkward things

# How to use a JavaScript lib

npm install --save @types/lodash
import * as _ from "lodash";
_.padStart("Hello TypeScript!", 20, " ");

Namespaces and Modules

// In a .d.ts file or .ts file that is not a module:
declare module "SomeModule" {
    export function fn(): string;
}

/// <reference path="myModules.d.ts" />
import * as m from "SomeModule";
export namespace Shapes {
    export class Triangle { /* ... */ }
    export class Square { /* ... */ }
}



import * as shapes from "./shapes";

// and instead of shapes.Shapes.Triangle(); without namespaces...
let t = new shapes.Triangle(); 

OK

I'm done talking now

Made with Slides.com