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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size 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 full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size 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 full-size slide