TypeScript

http://dotinstall.com/lessons/basic_typescript

  • マイクロソフト
  • TypeScript -> JavaScript
  • 静的な型付け
  • クラスベースのオブジェクト指向

http://www.typescriptlang.org/

インストール

sudo npm install -g typescript

  • main.ts
class User {
    
}

console.log("hello world");
tsc main.ts
  → main.js

node main.js

変数の静的型付け <-> 動的型付け(type script)

// TypeScript

var x: number = 10;
x = "hello";

/*
number
string
boolean
any
*/

var i: number;
var i: number = 10;
var i = 10; // i: number

var x; // var x: any
x = 10;
x = "hello";

var results: number[];
results = [10, 5, 3];

列挙型(わかり易く定数を表現)

/*
enum Signal {
    Red = 0,
    Blue = 1,
    Yellow = 2
}
*/

enum Signal {
    Red, // 0
    Blue = 3,
    Yellow // 4
}

enum Signal {
    Green = 5   // マージされる
}

var result: Signal;

// if (result === Signal.Yellow) { ... }
// if (result === Signal['Yellow']) { ... }

// console.log(Signal[2]); // Yellow
// console.log(Signal[3]); // Blue

console.log(Signal.Green); // 5

関数 - 静的型付け

  • 返り値がない void
  • 引数がオプション b?
function add(a: number, b: number): number {
    return a + b;
}

function add(a: number, b?: number): number {
    // b が無かった場合
    if (b) {
        return a + b;
    } else {
        return a + a;
    }
}

function add(a: number, b: number = 10): number {
    return a + b;
}

// console.log(add(5, 3));
// console.log(add(5, "hello"));
console.log(add(5, 3));
console.log(add(5));

関数式

var add = function(a: number, b: number): number {
    return a + b;
}

// アロー関数式( => )
var add = (a: number, b: number): number => {
    return a + b;
}

// リターンも省略可能
var add = (a: number, b: number): number => a + b;

console.log(add(5, 3));

関数のオーバーロード

function add(a: number, b: number): number; // シグネチャ(関数の引数と返り値のコンビ)
function add(a: string, b: string): string;

function add(a: any, b: any): any {
    if (typeof a === "string" && typeof b === "string") {
        return a + " " + b;
    }
    return a + b;
}

// console.log(add(5, 3)); // 8
// console.log(add("hello", "world")); // hello world

console.log(add("hello", 3));

クラス

// public, protected, private アクセス修飾子

class User {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
          ↓
    // コンストラクタでメンバ変数定義&設定
    constructor(public name: string) {
    }

    public sayHi(): void {
        console.log("hi! i am " + this.name);
    }
}

var tom = new User("Tom");
console.log(tom.name);
tom.sayHi();

GETTER, SETTER

class User {
    // private に変更
    constructor(private _name: string) {
    }
    public sayHi(): void {
        console.log("hi! i am " + this._name);
    }

    // GETTER(tom.name で取得) - ECMA5の機能
    get name() {
        return this._name;
    }

    // SETTER(tom.name = "TOM"; で設定)- ECMA5の機能
    set name(newValue: string) {
        this._name = newValue;
    }
}

var tom = new User("Tom");
console.log(tom.name);
tom.name = "TOM";
console.log(tom.name);
tom.sayHi();

ECMA5 コンパイル

tsc main.ts -t ES5

クラス継承

// public, protected, private

class User {
    constructor(protected _name: string) {
    }
    public sayHi(): void {
        console.log("hi! i am " + this._name);
    }
}

// extends で継承
class AdminUser extends User {
    private _age: number;
    constructor(_name: string, _age: number) {
        super(_name);
        this._age = _age;
    }

    public sayHi(): void {
        console.log("my age: " + this._age);
        console.log("my name: " + this._name);
        // 親クラスの SayHi 実行
        super.sayHi();
    }
}

var bob = new AdminUser("Bob", 23);
bob.sayHi();

静的メンバ static

  • メンバ:そのクラスの変数やメソッド
  • インスタンスではなく、class に保持されるメンバ
class User {
    name: string;
    constructor(name: string) {
        this.name = name;
        User.count++;
    }

    sayHi(): void {
        console.log("hi! i am " + this.name);
    }

    static count: number = 0;

    static showDescription(): void {
        console.log("this class is about users");
    }
}

var tom = new User("Tom");
var bob = new User("Bob");
console.log(User.count);
User.showDescription();

Interface

オブジェクトの型に名前をつけるもの

構造的部分型
ある型のプロパティを持っていれさえすれば、その「型」としてみなす

interface Result {
    a: number;
    b: number;
}

// 変数の型付け
function getTotal(result: {a: number, b: number}) {
    ↓
function getTotal(result: Result) {
    return result.a + result.b;
}

var result = {
    a: 32,
    b: 58,
    c: "hello"  // 構造的部分型
};

console.log(getTotal(result));

Interface

複数インターフェイスを継承可能

interface SpringResult {
    a: number;
}

interface FallResult {
    b: number;
}

interface FinalResult extends SpringResult, FallResult {
    final: number;
    // final?: number; // オプション指定
}

function getTotal(result: FinalResult) {
    // オプションの確認
    if (result.final) {
        return result.a + result.b + result.final;
    } else {
        return result.a + result.b;
    }
}

var result = {
    a: 32,
    b: 58
};

console.log(getTotal(result));

インターフェイスの実装

Interface と Class を紐付ける

interface GameUser {
    score: number;
    showScore(): void;
}

class User implements GameUser {
    name: string;
    score: number = 0;            // 実装しないtぽ行けない
    constructor(name: string) {
        this.name = name;
    }
    sayHi(): void {
        console.log("hi! i am " + this.name);
    }
    showScore(): void {           // 実装しないtぽ行けない
        console.log("score " + this.score);
    }
}

ジェネリクス

Generics: 抽象化されたデータ型

function getStringArray(value: string): string[] {
    return [value, value, value];
}

function getNumberArray(value: number): number[] {
    return [value, value, value];
}
function getArray<T>(value: T): T[] {
    return [value, value, value];
}

console.log(getArray<number>(3));       // 呼び出し側で「型」を指定
console.log(getArray<string>("hello")); // 呼び出し側で「型」を指定

ジェネリクスに制約を付与

class MyData<T> {
    constructor(public value: T) {}
    getArray(): T[] {
        return [this.value, this.value, this.value];
    }
}

var v1 = new MyData<string>("hello");
console.log(v1.getArray());
var v2 = new MyData<number>(234);
console.log(v2.getArray());
interface Result {
    a: number;
    b: number;
}

class MyData<T extends Result> {
    constructor(public value: T) {}
    getArray(): T[] {
        return [this.value, this.value, this.value];
    }
}

var v3 = new MyData<Result>({a: 32, b: 16});
console.log(v3.getArray());
interface Result {
    a: number;
    b: number;
}

interface FinalResult {
    a: number;
    b: number;
    c: string;
}

class MyData<T extends Result> {
    constructor(public value: T) {}
    getArray(): T[] {
        return [this.value, this.value, this.value];
    }
}

// a, b を持っていればOKなので、FinalResult もOK(構造的部分型)
var v4 = new MyData<FinalResult>({a: 32, b: 16, c: "hello"});
console.log(v4.getArray());

内部モジュール

module UserModule {
    export var name = "taguchi";   // export:外部に対して公開する
    export module AddressModule {
        export var zip = "111-1111";
    }
}

console.log(UserModule.name);
console.log(UserModule.AddressModule.zip);

// 短い名前に出来る
import addr = UserModule.AddressModule;
console.log(addr.zip);

main.ts

// スラッシュ3つでモジュール読み込み
/// <reference path="./user.ts" />

console.log(UserModule.name);

import addr = UserModule.AddressModule;
console.log(addr.zip);

user.ts

module UserModule {
    export var name = "taguchi";
    export module AddressModule {
        export var zip = "111-1111";
    }
}

コンパイル

tsc main.js --out all.js

外部モジュールを使ってみよう

  • Node - CommonJS
  • RequireJS - AMD

1ファイルに1モジュール
→ よって module定義 はいらない

user_commonjs.ts、user_amd.ts

exports.name = "taguchi";

CommonJS 形式

import User = require("./user_commonjs");

console.log(User.name);

コンパイル

tsc main.ts -m commonjs // CommonJS形式

AMD 形式

import User = require("./user_amd");

console.log(User.name);

コンパイル (AND形式)

tsc main.ts -m amd // AND形式