トップ 差分 一覧 ping ソース 検索 ヘルプ PDF RSS ログイン

TypeScript



目次



記事一覧

キーワード

このページは移動しました


TypeScript

[Node.js][Angular][Google Cloud Platform]



 準備

install

> npm install -g typescirpt

init

tsconfig.json の生成
> tsc --init

Visual Studio Code タスク

F1 - task run - build tsconfig.json

Playground

変数・型

 変数・定数

変数宣言 ブロックスコープ 同じスコープでの重複宣言 備考
var 認識しない 認める
let 認識する 認めない
const 認識する 認めない 再代入不可

 

説明
number 数値
string 文字列
boolean 真偽
symbol シンボル
any 任意
オブジェクト

 文字列リテラル

`バッククオートで囲む

  • 改行もそのまま
  • ${...} ...に変数、式を埋め込み
class Program {
    static main() {
        let name: string = "Hiroto Yagi";
        let age = 46;   // 型推論
        // age = "Hello"; // 数値型に文字列代入エラー
        let msg = null; // 初期値未指定、null指定など、any型と類推され型チェックは働かない
        msg = 100;      // noImplicitAny:true とすると、暗黙的 anyは許容しない
        msg = "Hello";
    
        // テンプレート文字列
        console.log(`
        ${msg} 
        my name is ${name} 
        age ${age}
        ${new Date()}`);
    }
}

Program.main();
結果
> node ./src/app.js

       Hello
       my name is Hiroto Yagi
       age 46
       toda Tue Nov 07 2017 18:59:23 GMT+0900 (東京 (標準時))

 型アサーション

  • キャスト
function show(message: string) {
    console.log(`${message}`);
}
class TypeAssartion {
    static main() {
        // show(10);    // ERROR
        show(<any>10);  // OK
        show(10 as any); // as もOK
    }
}

 コレクション/インターフェース

interface StringMap {
    [index:string]:string;
}
class Collection {
    static main() {
        // 配列
        let languages: string[] = ['java','C#','python'];
        console.log(languages);

        // 連想配列
        let fwMap: {[key:string]:string} = {
            'java':'Spring',
            'C#':'Asp.net',
            'python':'Django'
        };
        console.log(fwMap);

        // インデクスシグネチャはinterfaceとして事前定義可
        let fwMap2: StringMap = {
            'java':'Spring',
            'C#':'Asp.net',
            'python':'Django'
        };
        console.log(fwMap2);
    }
}

 列挙

enum Animal {
    DOG,
    CAT,
    MOUSE,
    ELEPHANT
}
enum Fruit {
    APPLE = "A",
    ORANGE = "O",
    PAINAPPLE = "P"
}
class EnumSample {
    static main() {
        let mypet: Animal = Animal.DOG;
        // デフォルトで0からの数値が割り当てられる
        console.log(mypet);
        console.log(Animal[mypet]);
        
        let myfavarit: Fruit = Fruit.PAINAPPLE;
        // 列挙子に値を割り当てることも可能
        console.log(myfavarit);
    }
}
結果
0
DOG
P

 タプル

let tpl: [string, number, boolean] = ['Yagi', 46, true];
console.log(`name:${tpl[0]} age:${tpl[1]} marriged:${tpl[2]}`);

 共用型

let data: string | boolean;
data = 'foo';// OK
data = true; // OK
// data = 1; // NG

let datas: (boolean | number)[] = [true, false, 1, 0];

 型エイリアス

// 主にタプル、共用型に別名を付与。インターフェースでできる場合に使用しないほうがよい
type ProfileTuple = [string, number, boolean];
let me = ['yagi', 46, true];        
console.log(`name:${me[0]} age:${me[1]} marriged:${me[2]}`);

 文字列リテラル

type Season = 'spring' | 'summer' | 'autumn' | 'winter';
class StringLiteralType {
    printSeason(s: Season) {
        console.log(s);
    }
    static main() {
        let me = new StringLiteralType();
        me.printSeason('summer');  // OK
        // me.printSeason('hoge'); // NG
    }
}

関数

  • function命令
  • 関数リテラル
  • アロー関数

 関数、関数リテラル、アロー関数

function squire(x: number, y: number) :number {
    return x * y;
}
class FunctionSample{
    static main() {
        // 関数の使用
        console.log(squire(8,8));

        // 関数リテラル(型推論)
        let m3 = function(x :number, y: number, z: number): number {
            return x * y * z;
        } ;
        console.log(m3(8,8,8));

        // 関数リテラル(型明示)
        let m2: (x: number, y: number) => number = function(x: number, y: number) {
            return x * y;
        };
        console.log(m2(9,9));
        
        // アロー関数(ラムダ式)
        // this は宣言された場所によって変わる
        let m22 = (x: number, y: number): number =>  x * y;
        console.log(m22(5,5));
    }
}

 引数の省略、デフォルト引数、可変長引数

class FunctionApplySample {
    static main(){
        // TypeScriptでは宣言された引数はすべて必須
        // 引数を省略したい場合、仮引数の名前の後ろに ? を付与
        let greet = function(message?: string){
            message = (message === undefined)?"hello":message;
            console.log(message);
        }
        greet();
        greet("good evening");
    
        // 関数のデフォルト値を設定するには、仮引数の後に=デフォルト値
        // デフォルト値には、式も利用できる
        // 明示的に undefined を渡した場合もデフォルト値が利用される
        let greet2 = function(message: string=`hello ${new Date()}`) {
            console.log(message);
        }
        greet2();
        greet2("good night");
        greet2(undefined);

        // 可変長引数
        // 仮引数の前に、... とすることで可変長引数となる
        let sum = function(...nums: number[]):number {
            let ttl: number = 0;
            nums.forEach((value,index,array) => ttl += value);
            return ttl;
        }
        console.log(sum(1,2,3,4,5));
    }
}

 関数のオーバーロード

function showMessage(value: number): void;
function showMessage(value: boolean): void;
function showMessage(value: any): void {
    let message: string | undefined;
    if (typeof value === 'number') {
        message = `${value} is number.`;
    }
    if (typeof value === 'boolean') {
        message = `${value} is boolean`;
    }
    console.log(message);
}
class FunctionApplySample2 {
    static main(){
        console.log("*** 関数応用2 ***");
        // 1.シグネチャのみの関数を用意
        // 2.具体的な実装を直後に定義
        // 3.実装の中で、typeof/instanceof を用いて型を判定し処理を記述
        showMessage(123);
        showMessage(false);
        showMessage("Hello" as any);
    }
}

オブジェクト指向

 クラス定義

class Person {
    // メンバー
    name: string; // デフォルト public
    private _age: number; 

    // 静的メンバー
    public static CHEAT_AGES: number = 2;
    
    // コンストラクター
    constructor(name: string, age: number){
        this.name = name;
        this._age = age;
    }

    // 以下のコンストラクターでメンバーの宣言と代入を省略できる
    // アクセス修飾子必須
    // constructor(public name: string, private _age: number) {
    // }

    // アクセッサー
    get age(): number {
        return this._age - Person.CHEAT_AGES;
    }
    set age(value: number) {
        this._age = value;
    }

    // メソッド
    printProfile(){
        console.log(`name=${this.name},age=${this.age}`);
    }
}
console.log(Person.CHEAT_AGES);
let me = new Person('Yagi', 46);
//console.log(me.age); // NG
me.printProfile();
me.age = 50;
me.printProfile();
結果
2
name=Yagi,age=44
name=Yagi,age=48

 名前空間

  • namespace ブロックで定義
  • exportで外側からアクセス可能なことを明示
  • 完全修飾名で呼び出す
namespace NameA {
    export class Foo {
        name() {
            console.log("NameA.Foo");
        }
    }
    export function bar(){
        console.log("NameA.bar()");
    }
}
let foo = new NameA.Foo();
foo.name();
NameA.bar();

名前空間のネスト

namespace NameB {
    export namespace NameC {
        export function bar(){
            console.log("NameB.NameC.bar()");
        }
    }
}
NameB.NameC.bar(); 

 継承

class Guiter {
    constructor(public maker: string, public type: string){}
    print() {
        console.log(`${this.type} by ${this.maker}`);
    }
}
class Lespaul extends Guiter {
    constructor(){
        super("Gibson","Lespaul");
    }
}
(new Lespaul()).print();

 抽象クラス

// 抽象クラス
abstract class Viecle {
    // 抽象メソッド
    abstract getEngineDisplacement(): number;
    printDisplacement() {
        console.log(`${this.getEngineDisplacement()}`);
    }
}
class Premacy extends Viecle {
    // 抽象メソッドのオーバーライド
    getEngineDisplacement(): number {
        return 2000;
    }
    // メソッドオーバーライド
    printDisplacement() {
        console.log("******");
        super.printDisplacement();
        console.log("******");
    }
}
(new Premacy()).printDisplacement();

 インターフェース

interface Color {
    // メソッドはすべて抽象メソッド
    // abstract 指定は不要
    getRGB(): string;
}
class Red implements Color {
    getRGB(): string {
        return "#FF0000";
    }
}
console.log((new Red()).getRGB());

 構造的部分型(Structual subtyping)

class Hoge {
    constructor(public name: string, public age: number){}
}
class Spam {
    constructor(public name: string, public age: number){}
}
// 継承による明示的な互換性(Nominal subtyping)がなくても構造が一致していれば代入可能
let h: Hoge = new Spam("spam",10);
console.log(h);

 型注釈としてのインターフェース

  • インターフェースを型注釈として利用できる
interface Shape {
    // プロパティシグネチャ
    name: string;
    // メソッドシグネチャ
    draw():void;
}
let c : Shape = {
    name:'circle',
    draw() {
        console.log(`${this.name}:○`);
    } 
};
c.draw();

オブジェクトリテラル

  • インターフェースを定義するまでもないが、型情報は明示しておきたい場合
let t : { name: string, sides: number} = {name: 'triangle', sides: 3};

 型としてのthis

class StringBuilder {
    constructor(protected _value: string){
    }
    toString(): string {
        return this._value;
    }
    wrap(value: string) :string{
        return `${value}`;
    }
    // 自分自身を返すことで、メソッドチェーンのような記述が可能となる
    // 派生クラスなど、呼び出し元のクラスに応じ型が変化する
    append(value: string): this {
        this._value = this._value + this.wrap(value);
        return this;
    }
}
let buf = new StringBuilder('a');
buf.append('b').append('c').append('d');
console.log(buf.toString());

class CsvBuilder extends StringBuilder {
    constructor(protected _value: string){
        super(_value);
    }
    wrap(value: string) {
        return `,${value}`;
    }
}
let csv = new CsvBuilder('a');
csv.append('b').append('c').append('d');
console.log(csv.toString());
出力
abcd
a,b,c,d

 ジェネリック

let numary: Array<number> = [1,2,3,5,8];

ジェネリック型の定義

  • StringBuilder型は、上記で定義参照
class XmlBuilder extends StringBuilder {
    constructor(protected _value: string){
        super(_value);
    }
    wrap(value: string) {
        return `<value>${value}</value>`;
    }
    toString(): string {
        return `<values>${this._value}</values>`;
    }
}

// 型引数に制約を付与する場合、extends を使用する。
// 使用しなければ、あらゆる型を渡すことができる
class Report<T extends StringBuilder> {
    builder: T;
    getBuilder(): T {
        return this.builder;
    }
    addLine(line: string) {
        this.getBuilder().append(line);
    }
    report() {
        console.log(this.getBuilder().toString());
    }
}
let rep = new Report<XmlBuilder>();
// ジェネリック型に具体的なインスタンスを紐づけ
rep.builder = new XmlBuilder('');
rep.addLine("this is lesson.");
rep.addLine("of TypeScript.")
rep.report();
出力例
<values><value>this is lesson.</value><value>of TypeScript.</value></values> 

ジェネリックメソッド

function reverse<T>(data: T[]): T[] {
    let ary: T[] = new Array();

    let j=0;
    for(let i=data.length-1; i>=0; i--) {
        ary[j++] = data[i];
    }
    return ary;
}
console.log(reverse<number>([1,2,3,4]));
console.log(reverse<string>(["a","b","c","d"]));
出力例
[ 4, 3, 2, 1 ]
[ 'd', 'c', 'b', 'a' ]

 サンプル

app.ts(642)

Tips

 TypeDoc

インストール

> npm install typedoc -g

作成

> typedoc --out ./docs/ ./src/ --module commonjs



YAGI Hiroto (piroto@a-net.email.ne.jp)
twitter http://twitter.com/pppiroto

Copyright© 矢木 浩人 All Rights Reserved.