Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to TypeScript

Introduction to TypeScript

Samantha Quiñones

July 14, 2016
Tweet

More Decks by Samantha Quiñones

Other Decks in Technology

Transcript

  1. Introduction to TypeScript
    Samantha Quiñones, Open West 2016

    View Slide

  2. Samantha Quiñones
    Principal Software Engineer
    Code and Community Champion
    AOL Inc.
    @ieatkillerbees
    @squinones
    ɂ http://squinones.github.io
    ɔ https://joind.in/talk/bedf8

    View Slide

  3. What is Typescript?
    • Superset of JavaScript (all valid JavaScript is valid TypeScript)
    • Provides features from upcoming ECMAScript standards versions
    • Adds optional strict typing
    • Adopted by a number of projects, Angular 2 prominently
    • Microsoft
    • http://www.typescriptlang.org

    View Slide

  4. Why use TypeScript?
    • You want to use features of modern EMCA standards now
    • You want to make your complex JavaScript apps more robust

    View Slide

  5. About You
    • You are familiar with JavaScript
    • You have not worked extensively with statically typed languages
    • You are familiar with the build pipeline tools appropriate to your
    projects or environment (or are willing to talk after the session)

    View Slide

  6. Things I Won’t Cover
    • Workflow
    • Decorators
    • JSX

    View Slide

  7. Static vs Dynamic Typing
    […] strong typing is modestly better than weak typing, and […] static
    typing is also somewhat better than dynamic typing.
    Ray, B., Posnett, D., Filkov, V., Devanbu, P. T. (2014). A Large Scale Study of Programming Languages and Code Quality in Github

    View Slide

  8. Dynamic Typing
    function div(a, b) {
    return a/b;
    }
    console.log(div("a", "b"));

    View Slide

  9. Static Typing
    function div(a:number, b:number): number {
    return a/b;
    }
    console.log(div("a", "b"));

    View Slide

  10. Static Typing
    function div(a:number, b:number): number {
    return a/b;
    }
    console.log(div("a", "b"));
    function div(a, b) {
    return a / b;
    }
    console.log(div("a", "b"));
    //# sourceMappingURL=typed.js.map

    View Slide

  11. Static Typing
    function div(a:number, b:number): number {
    return a/b;
    }
    console.log(div("a", "b"));
    function div(a, b) {
    return a / b;
    }
    console.log(div("a", "b"));
    //# sourceMappingURL=typed.js.map

    > $ tsc examples/typed.ts
    examples/typed.ts(5,17): error
    TS2345: Argument of type 'string' is
    not assignable to parameter of type
    'number'.

    View Slide

  12. Reasons I Prefer Static Typing
    • Get more out of my IDE (I’m looking at you, JetBrains)
    • Slightly more verbose code is more explicit and I believe in 

    explicit > implicit
    • Allows the potential for fewer tedious tests. But testing is still vital.

    View Slide

  13. Basic Types - Booleans
    let isBoolean:boolean = true;

    View Slide

  14. Basic Types - Numbers
    let decimal:number = 42;
    let hexadecimal:number = 0x2A;
    let binary:number = 0b101010;
    let octal:number = 0o52;

    View Slide

  15. Basic Types - Strings
    let firstName:string = "Samantha";
    let greeting:string = `Hello, my name is ${ firstName }!`;
    let greeting:string = "Hello, my name is " + firstName + "!";

    View Slide

  16. Basic Types - Arrays
    let names:string[] = ["Joe", "Sally"];
    let ages:number[] = [28, 32];
    let heights:Array = [71, 66];

    View Slide

  17. Basic Types - Tuples
    let coords:[number, number] = [42, 21];
    let params:[string, number] = ["height", 72];

    View Slide

  18. Basic Types - Enums
    enum Status {Inactive, Active}
    let status: Status = Status.Inactive;

    View Slide

  19. Basic Types - Void
    let nothing:void = undefined;
    function doNothing(): void {
    // do nothing!
    }

    View Slide

  20. The “Any” Type
    let anything:any = "foo";

    View Slide

  21. The “Any” Type
    let anything:any = "foo";
    function combine(a, b) {
    return a + b;
    }
    let foo = 42;
    let bar = "fred";
    console.log(combine(foo, bar));
    function combine(a:any, b:any):any {
    return a + b;
    }
    let foo:number = 42;
    let bar:string = "fred";
    console.log(combine(foo, bar));

    View Slide

  22. Type Assertions
    let anyValue: any = "This value is a string!";
    let stringLength: number = anyValue.length; // angle bracket style
    let stringLength: number = (anyValue as string).length; // JSX-style

    View Slide

  23. Variables
    • var - execution/global scope
    • let - block/local scope

    View Slide

  24. let vs. var
    function blockscope() {
    for( let i = 0; i < 5; i++ ) {
    console.log(i);
    }
    console.log(i);
    }
    function executionscope() {
    for( var i = 0; i < 5; i++ ) {
    console.log(i)
    }
    console.log(i);
    }

    View Slide

  25. let vs. var
    for (var i = 0; i < 10; i++) {
    setTimeout(function() {console.log(i); }, 100 * i);
    }

    View Slide

  26. let vs. var
    for (var i = 0; i < 10; i++) {
    setTimeout(function() {console.log(i); }, 100 * i);
    }
    > $ node examples/letloop.js
    10
    10
    10
    10
    10
    10
    10
    10
    10
    10

    View Slide

  27. let vs. var
    for (var i = 0; i < 10; i++) {
    (function(i) {
    setTimeout(function() { console.log(i); }, 100 * i);
    })(i);
    }

    View Slide

  28. let vs. var
    for (var i = 0; i < 10; i++) {
    (function(i) {
    setTimeout(function() { console.log(i); }, 100 * i);
    })(i);
    }
    > $ node examples/letloop.js
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

    View Slide

  29. let vs. var
    for (let i = 0; i < 10 ; i++) {
    setTimeout(function() {console.log(i); }, 100 * i);
    }

    View Slide

  30. let vs. var
    > $ node examples/letloop.js
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    for (let i = 0; i < 10 ; i++) {
    setTimeout(function() {console.log(i); }, 100 * i);
    }

    View Slide

  31. let vs. var
    for (let i = 0; i < 10 ; i++) {
    setTimeout(function() {console.log(i); }, 100 * i);
    }
    var _loop_1 = function(i) {
    setTimeout(function () { console.log(i); }, 100 * i);
    };
    for (var i = 0; i < 10; i++) {
    _loop_1(i);
    }

    View Slide

  32. Constants
    var foo = 42;
    function timesFoo(a) {
    return foo * a;
    }
    console.log(timesFoo(2));
    const foo:number = 42;
    function timesFoo(a:number): number {
    return foo * a;
    }
    console.log(timesFoo(2));

    View Slide

  33. Constants
    const foo:number = 42;
    function timesFoo(a:number): number {
    return foo * a;
    }
    foo = 1701;
    console.log(timesFoo(2));
    var foo = 42;
    function timesFoo(a) {
    return foo * a;
    }
    foo = 1701;
    console.log(timesFoo(2));
    > $ tsc examples/consts.ts
    examples/consts.ts(8,1): error TS2450: Left-
    hand side of assignment expression cannot be
    a constant.

    View Slide

  34. Interfaces
    interface Meat {
    isCooked:boolean;
    sourceAnimal:string;
    }
    function cookMeat(meat:Meat): Meat {
    meat.isCooked = true;
    return meat;
    }
    let sirloin:Meat = {
    isCooked: false,
    sourceAnimal: "cattle"
    };
    cookMeat(sirloin);
    console.log(sirloin.isCooked);

    View Slide

  35. Interfaces - Optional Properties
    interface Meat {
    isCooked:boolean;
    isGame:boolean;
    sourceAnimal:string;
    gaminess?:number;
    }
    function cookMeat(meat:Meat):Meat {
    meat.isCooked = true;
    return meat;
    }
    let sirloin:Meat = {
    isCooked: false,
    isGame:false,
    sourceAnimal: "cattle"
    };
    cookMeat(sirloin);
    console.log(sirloin.isCooked);
    let venison:Meat = {
    isCooked: false,
    isGame:true,
    sourceAnimal: "deer",
    gaminess: 3
    };
    cookMeat(venison);
    console.log(venison.isCooked);

    View Slide

  36. Interfaces - Undefined Properties
    let venison:Meat = {
    isCooked: false,
    isGame:true,
    sourceAnimal: "deer",
    gameiness: 3
    };
    cookMeat(venison);
    console.log(venison.isCooked);
    examples/recipes/meat.ts(23,5): error TS2322: Type '{ isCooked: boolean; isGame:
    boolean; sourceAnimal: string; gameiness: number; }' is not assignable to type 'Meat'.
    Object literal may only specify known properties, and 'gameiness' does not exist in
    type 'Meat'.

    View Slide

  37. Interfaces - Index Signatures
    interface Meat {
    isCooked:boolean;
    isGame:boolean;
    sourceAnimal:string;
    gaminess?:number;
    [otherProperty: string]: any;
    }
    let ChickenBreast:Meat = {
    isCooked: false,
    isGame: false,
    sourceAnimal: "chicken",
    skinless: true
    };

    View Slide

  38. Interfaces - Function Interfaces
    interface Ingredient {
    name: string;
    }
    interface MixedIngredient {
    ingredients: Ingredient[];
    }
    interface MixFunction {
    (ingredients:Ingredient[], speed:number): MixedIngredient;
    }
    let mixer:MixFunction = function (ingredients:Ingredient[], speed:number): MixedIngredient {
    return {
    ingredients: ingredients
    };
    };
    let mixed = mixer([{name: "flour"}, {name: "sugar"}], 10);
    console.log(mixed);

    View Slide

  39. Interfaces - Indexed Types
    interface Ingredient {
    name: string;
    }
    interface IngredientList {
    [index: number]: Ingredient
    }
    interface MixFunction {
    (ingredients:Ingredient[], speed:number): any;
    }
    interface MixFunction2 {
    (ingredients:IngredientList, speed: number): any;
    }

    View Slide

  40. Interfaces - Indexed Types
    interface Ingredient {
    name: string,
    quantity: number,
    unit: string
    }
    interface RecipeDictionary {
    [index: string]: Ingredient
    }

    View Slide

  41. Interfaces - Indexed Types
    interface Ingredient {
    name: string,
    quantity: number,
    unit: string
    }
    interface RecipeDictionary {
    [index: string]: Ingredient
    name: string;
    }
    > $ tsc examples/dictionary.ts
    examples/dictionary.ts(9,5): error TS2411: Property 'name' of type 'string' is not
    assignable to string index type 'Ingredient'.

    View Slide

  42. Interface Extension
    interface Meat {
    isCooked:boolean;
    sourceAnimal:string;
    [otherProperty: string]: any;
    }
    interface Game extends Meat {
    gaminess:number;
    }
    let GroundChuck:Meat = {
    isCooked:false,
    sourceAnimal: "cattle"
    };
    let DuckBreast:Game = {
    isCooked:false,
    sourceAnimal: "duck",
    gaminess: 3
    };

    View Slide

  43. Implementing Interfaces
    interface Mixer {
    mix:MixFunction,
    clean(): void
    }
    class KitchenAid implements Mixer {
    }
    > $ tsc examples/implementing-interfaces.ts
    examples/implementing-interfaces.ts(18,7): error TS2420: Class 'KitchenAid'
    incorrectly implements interface 'Mixer'.
    Property 'mix' is missing in type 'KitchenAid'.

    View Slide

  44. Implementing Interfaces
    interface Mixer {
    mix:MixFunction,
    clean(): void
    }
    class KitchenAid implements Mixer {
    mix(ingredients:Ingredient[], speed:number): MixedIngredient {
    return { ingredients: ingredients };
    };
    clean(): void {
    //
    }
    }

    View Slide

  45. Classes
    class Ingredient {
    name:string;
    unit:string;
    quantity:number;
    constructor(name:string, unit:string, quantity:number) {
    this.name = name;
    this.unit = unit;
    this.quantity = quantity;
    }
    recipeString(): string {
    return `${this.name} - ${this.quantity} ${this.unit}`;
    }
    }
    let flour = new Ingredient("flour", "cup", 1);

    View Slide

  46. Classes
    var Ingredient = (function () {
    function Ingredient(name, unit, quantity) {
    this.name = name;
    this.unit = unit;
    this.quantity = quantity;
    }
    Ingredient.prototype.recipeString = function () {
    return this.name + " - " + this.quantity + " " + this.unit;
    };
    return Ingredient;
    })();
    var flour = new Ingredient("flour", "cup", 1);

    View Slide

  47. Inheritance in JavaScript
    • JavaScript uses prototypal inheritance
    • Inherited properties come from a linked object (the prototype)
    • The prototype model can be used to implement classical inheritance
    • ES6 (and TypeScript) introduce a “class” keyword that provides
    syntactic sugar for creating classical inheritance chains using
    prototypes

    View Slide

  48. Classes - Inheritance
    enum FlourType { White, Wheat, Rye, Corn }
    class Flour extends Ingredient {
    type:FlourType;
    constructor(name:string, unit:string, quantity:number, type:FlourType) {
    super(name, unit, quantity);
    this.type = type;
    }
    }
    let wheatFlour = new Flour("flour", "cup", 1, FlourType.Wheat);

    View Slide

  49. Classes - Inheritance
    var FlourType;
    (function (FlourType) {
    FlourType[FlourType["White"] = 0] = "White";
    FlourType[FlourType["Wheat"] = 1] = "Wheat";
    FlourType[FlourType["Rye"] = 2] = "Rye";
    FlourType[FlourType["Corn"] = 3] = "Corn";
    })(FlourType || (FlourType = {}));
    var Flour = (function (_super) {
    __extends(Flour, _super);
    function Flour(name, unit, quantity, type) {
    _super.call(this, name, unit, quantity);
    this.type = type;
    }
    return Flour;
    })(Ingredient);
    var wheatFlour = new Flour("flour", "cup", 1, FlourType.Wheat);
    //# sourceMappingURL=inheritance.js.map

    View Slide

  50. Classes - Abstracts
    abstract class Ingredient {
    constructor(protected name:string) {}
    abstract printRecipeString(): string;
    }
    class OliveOil extends Ingredient {
    constructor() {
    super("Olive Oil");
    }
    printRecipeString():string {
    return `${this.name}`;
    }
    }

    View Slide

  51. Classes - Extending
    class Ingredient {
    name:string;
    unit:string;
    quantity:number;
    }
    interface Oil extends Ingredient {
    viscosity:number;
    }

    View Slide

  52. Classes - Visibility
    class Ingredient {
    name:string;
    unit:string;
    quantity:number;
    }
    class Ingredient {
    public name:string;
    public unit:string;
    public quantity:number;
    }

    View Slide

  53. Classes - Visibility
    class Ingredient {
    name:string;
    unit:string;
    quantity:number;
    }
    class Ingredient {
    public name:string;
    public unit:string;
    public quantity:number;
    }
    ==
    • Public properties are visible to any caller
    • Protected properties are visible to a class instance and its children
    • Private properties are visible only to a class instance

    View Slide

  54. Classes - Private Members
    class Ingredient {
    private _name:string;
    private _unit:string;
    private _quantity:number;
    constructor(name:string, unit:string, quantity:number) {
    this._name = name;
    this._unit = unit;
    this._quantity = quantity;
    }
    }
    let butter= new Ingredient("butter", "tbsp", 2);
    butter._unit = "cup";
    > $ tsc examples/classes/private.ts
    examples/classes/private.ts(14,1): error TS2341: Property '_unit' is private and only
    accessible within class 'Ingredient'.

    View Slide

  55. Classes - Private Members
    class Ingredient {
    private _name:string;
    constructor(name:string) { this._name = name; }
    }
    class Butter extends Ingredient { constructor() { super(“Butter"); } }
    class Condiment {
    private _name:string;
    constructor(name:string) { this._name = name; }
    }
    let ingredients:Ingredient[] = [new Butter(), new Condiment("Ketchup")];

    View Slide

  56. Classes - Private Members
    class Ingredient {
    private _name:string;
    constructor(name:string) { this._name = name; }
    }
    class Butter extends Ingredient { constructor() { super(“Butter"); } }
    class Condiment {
    private _name:string;
    constructor(name:string) { this._name = name; }
    }
    let ingredients:Ingredient[] = [new Butter(), new Condiment("Ketchup")];
    > $ tsc examples/classes/private.ts
    examples/classes/private.ts(23,5): error TS2322: Type '(Butter | Condiment)[]' is not
    assignable to type 'Ingredient[]'.
    Type 'Butter | Condiment' is not assignable to type 'Ingredient'.
    Type 'Condiment' is not assignable to type 'Ingredient'.
    Types have separate declarations of a private property '_name'.

    View Slide

  57. Classes - Protected Members
    class Ingredient {
    private _name:string;
    private _unit:string;
    constructor(name:string) {
    this._name = name;
    }
    }
    class Butter extends Ingredient {
    constructor() {
    super("Butter");
    this._unit = "tbsp";
    }
    }
    let butter = new Ingredient("butter");
    > $ tsc examples/classes/protected.ts
    examples/classes/protected.ts(12,9): error
    TS2341: Property '_unit' is private and only
    accessible within class 'Ingredient'.

    View Slide

  58. Classes - Protected Members
    > $ tsc examples/classes/protected.ts
    examples/classes/protected.ts(17,1): error
    TS2445: Property '_unit' is protected and only
    accessible within class 'Ingredient' and its
    subclasses.
    class Ingredient {
    private _name:string;
    protected _unit:string;
    constructor(name:string) {
    this._name = name;
    }
    }
    class Butter extends Ingredient {
    constructor() {
    super("Butter");
    this._unit = "tbsp";
    }
    }
    let butter= new Ingredient("butter");
    butter.unit = "cup";

    View Slide

  59. Classes - Static Properties
    class Ingredient {
    private grams:number;
    static gramsPerOunce:number = 28.35;
    getWeightInGrams():number {
    return this.grams;
    }
    }
    let butter = new Ingredient();
    let ounces = butter.getWeightInGrams() * Ingredient.gramsPerOunce;

    View Slide

  60. Classes - Static Properties
    function Ingredient() {}
    Ingredient.prototype.foo = function () {};
    Ingredient.bar = function () {};
    Ingredient.bar(); // static property

    View Slide

  61. Functions
    function namedAdd(a:number, b:number): number { return a+b; }
    let anonymousAdd = function (a:number, b:number): number { return a+b; };
    // reference parameter list return type definition
    let fullAdd: (a:number, b:number) => number = function (a:number, b:number): number {
    return a+b;
    };

    View Slide

  62. Functions - Optionals & Defaults
    function incrementOptional(base:number, incrementBy?:number) {
    return base + incrementBy || 1;
    }
    function incrementDefaulted(base:number, incrementBy:number=1): number {
    return base + incrementBy;
    }

    View Slide

  63. Functions - Variadic Parameters
    interface Ingredient {}
    interface IngredientList {
    ingredients:Ingredient[];
    }
    function createIngredientList(...ingredients:Ingredient[]): IngredientList {
    let list = {
    ingredients:[]
    };
    for (let ingredient of ingredients) {
    list.ingredients.push(ingredient);
    }
    return list;
    }

    View Slide

  64. Functions - Overloading
    function cook(ingredients:IngredientList, cookingAppliance:any, ...options:Array): Meal {
    if (typeof cookingAppliance === "Skillet") {
    return new SkilletMeal(ingredients);
    } else if (typeof cookingAppliance === "Crockpot") {
    return new CrockpotMeal(ingredients, options[0], options[1]);
    }
    }

    View Slide

  65. Functions - Overloading
    function cook(ingredients:IngredientList, crockpot:Crockpot, temp:number, time:number): CrockpotMeal;
    function cook(ingredients:IngredientList, skillet:Skillet): SkilletMeal;
    function cook(ingredients:IngredientList, cookingAppliance:any, ...options:Array): Meal {
    if (typeof cookingAppliance === "Skillet") {
    return new SkilletMeal(ingredients);
    } else if (typeof cookingAppliance === "Crockpot") {
    return new CrockpotMeal(ingredients, options[0], options[1]);
    }
    }
    let skillet = cook(new IngredientList(), new Skillet());
    let crockpost = cook(new IngredientList(), new Crockpot(), 225, 360);
    let dutchoven = cook(new DutchOven());
    > $ tsc examples/functions/overload.ts
    examples/functions/overload.ts(19,17): error TS2346: Supplied parameters do not match any signature
    of call target.

    View Slide

  66. Lambdas
    let recipe = {
    ingredients: [ "flour", "water", "eggs", "butter" ],
    createWriter: function () {
    return function () {
    return this.ingredients.join("\n");
    }
    }
    };

    View Slide

  67. Lambdas
    let recipe = {
    ingredients: [ "flour", "water", "eggs", "butter" ],
    createWriter: function () {
    return () => {
    return this.ingredients.join("\n");
    }
    }
    };

    View Slide

  68. Lambdas
    var recipe = {
    ingredients: ["flour", "water", "eggs", "butter"],
    createWriter: function () {
    return function () {
    return this.ingredients.join("\n");
    };
    }
    };
    var recipe = {
    ingredients: ["flour", "water", "eggs", "butter"],
    createWriter: function () {
    var _this = this;
    return function () {
    return _this.ingredients.join("\n");
    };
    }
    };

    View Slide

  69. Generics
    • Allow flexibility in strictly typed systems
    • Allows type resolution at runtime through the use of generic
    components

    View Slide

  70. Generics
    class Recipe {
    ingredients:Ingredient[];
    add(ingredient:Ingredient) { this.ingredients.push(ingredient); }
    }
    class VeganRecipe extends Recipe {
    ingredients:VeganIngredient[];
    add(ingredient:VeganIngredient) { this.ingredients.push(ingredient); }
    }
    let veganRecipe = new VeganRecipe();
    veganRecipe.add(new VeganIngredient());
    veganRecipe.add(new MeatIngredient()); // error

    View Slide

  71. Generics
    class Recipe {
    ingredients:Ingredient[];
    add(ingredient:Ingredient) { this.ingredients.push(ingredient); }
    }
    class VeganRecipe extends Recipe {
    ingredients:VeganIngredient[];
    add(ingredient:VeganIngredient) { this.ingredients.push(ingredient); }
    }
    class MeatRecipe extends Recipe {
    ingredients:MeatIngredient[];
    add(ingredient:MeatIngredient) { this.ingredients.push(ingredient); }
    }
    let meatRecipe = new MeatRecipe();
    meatRecipe.add(new MeatIngredient());
    let veganRecipe = new VeganRecipe();
    veganRecipe.add(new VeganIngredient());
    veganRecipe.add(new MeatIngredient()); // error

    View Slide

  72. Generics
    class Recipe {
    ingredients:T[];
    add(ingredient:T) {
    this.ingredients.push(ingredient);
    }
    }
    let meatRecipe = new Recipe();
    meatRecipe.add(new MeatIngredient());
    let veganRecipe = new Recipe();
    veganRecipe.add(new VeganIngredient());
    veganRecipe.add(new MeatIngredient()); // error

    View Slide

  73. Generics
    class Recipe {
    ingredients:T[];
    add(ingredient:T) {
    this.ingredients.push(ingredient);
    }
    }
    let badRecipe = new Recipe();
    badRecipe.add(new BadIngredient());
    > $ tsc examples/generics/generics.ts
    examples/generics/generics.ts(51,28): error TS2344: Type 'BadIngredient' does
    not satisfy the constraint 'Ingredient'.

    View Slide

  74. Unions
    interface Chicken {
    boned:boolean;
    pluck(): void;
    fillet(): Meat;
    }
    interface Fish {
    boned:boolean;
    scale(): void;
    fillet(): Meat;
    }
    function fillet(animal:Chicken|Fish): Meat {
    return animal.fillet();
    }

    View Slide

  75. Unions
    function fillet(animal:Chicken|Fish): Meat {
    if (animal.pluck) {
    animal.pluck();
    }
    if (animal.scale) {
    animal.scale();
    }
    return animal.fillet();
    }
    > $ tsc examples/unions.ts
    examples/unions.ts(13,16): error TS2339: Property 'pluck' does not exist on type 'Chicken | Fish'.
    examples/unions.ts(14,16): error TS2339: Property 'pluck' does not exist on type 'Chicken | Fish'.
    examples/unions.ts(16,16): error TS2339: Property 'scale' does not exist on type 'Chicken | Fish'.
    examples/unions.ts(17,16): error TS2339: Property 'scale' does not exist on type 'Chicken | Fish'.

    View Slide

  76. Unions
    function fillet(animal:Chicken|Fish): Meat {
    if ((animal).pluck) {
    (animal).pluck();
    }
    if ((animal).scale) {
    (animal).scale();
    }
    return animal.fillet();
    }
    \

    View Slide

  77. Type Guards & Predicates
    function isChicken(animal:Chicken|Fish): animal is Chicken {
    return (animal).pluck !== undefined;
    }
    function isFish(animal:Chicken|Fish): animal is Fish {
    return (animal).scale !== undefined;
    }
    function fillet(animal:Chicken|Fish): Meat {
    if (isChicken(animal)) {
    animal.pluck();
    }
    if (isFish(animal)) {
    animal.scale();
    }
    return animal.fillet();
    }

    View Slide

  78. Intersections
    interface Meat {
    sourceAnimal:string
    }
    interface Game {
    gaminess:number
    }
    function prepareGameMeat(meat:Meat&Game): PreparedMeat {
    return new PreparedMeat(meat);
    }

    View Slide

  79. Mixins
    interface Loggable {
    log(level:string, message:string): void
    }
    interface Serializable {
    serialize(): string
    }
    class ThingDoer implements Loggable, Serializable{
    log(level:string, message:string):void {
    logTheThing();
    }
    serialize():string {
    return "serialized ThingDoer!";
    }
    }
    function doThing(thing:Loggable&Serializable): string {
    thing.log('info', 'Doing the thing!');
    return thing.serialize();
    }

    View Slide

  80. Type Aliases
    type Unit = string;
    type UnitConverter = (Unit, value:number) => number;
    type WhiteMeat = Fish | Poultry;
    type Coords = [number,number,number];
    type KosherMeat = "cattle" | "goat" | "sheep" | "chicken" | "duck" | "goose"
    type LinkedList = T & { next: LinkedList };
    interface Ingredient {
    name:string;
    }
    var ingredients:LinkedList;
    ingredients.next.name;
    ingredients.next.next.name;

    View Slide

  81. String Types
    // code copyright Microsoft 2012-2016
    type Easing = "ease-in" | "ease-out" | "ease-in-out";
    class UIElement {
    animate(dx: number, dy: number, easing: Easing) {
    if (easing === "ease-in") {
    // ...
    }
    else if (easing === "ease-out") {
    }
    else if (easing === "ease-in-out") {
    }
    else {
    // error! should not pass null or undefined.
    }
    }
    }
    let button = new UIElement();
    button.animate(0, 0, "ease-in");
    button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here

    View Slide

  82. Modules
    export interface Meat {}
    export class Beef implements Meat {}
    export class Chicken implements Meat {}
    import * as meats from './meats';
    let chicken = new meats.Chicken();

    View Slide

  83. Namespaces
    namespace Meats {
    export interface Meat {}
    export class Beef implements Meat {}
    export class Chicken implements Meat {}
    }
    let chicken = new Meats.Chicken();

    View Slide

  84. Declarations
    • Allow us to describe the shape of objects defined outside a TS app
    • https://github.com/typings/typings
    • https://github.com/typings/registry

    View Slide

  85. Declarations
    // declaration for https://github.com/jonschlinkert/pad-left
    declare function padLeft (str: string, num: number, ch?: string): string;
    export = padLeft;

    View Slide

  86. tsconfig.json
    • Configures compiler options
    • Presence indicates the root of a TypeScript project

    View Slide

  87. tsconfig.json
    {
    "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "outDir": "built/",
    "sourceMap": true
    },
    "exclude": [
    "node_modules"
    ]
    }

    View Slide

  88. Thank you for listening!
    Rate speakers & the event!
    Questions?
    Samantha Quiñones
    @ieatkillerbees
    @squinones
    ɂ http://squinones.github.io
    ɔ https://joind.in/talk/bedf8

    View Slide