M.Hiroi's Home Page

JavaScript Programming

お気楽 TypeScript 超入門

[ Home | Light | JavaScript | TypeScript ]

TypeScript の基礎知識

TypeScript は JavaScript の仕様 ECMAScript2015 (ES2015) のスーパーセットです。ES2015 は拙作のページ お気楽 ECMAScript2015 超入門 で説明しています。本文中の [ES2015] は拙作のページへのリンクを表しています。よろしければお読みくださいませ。

●基本的なデータ型

●変数

リスト : データ型のチェック

let num: number;
num = "hello, world";
console.log(num);
C>tsc test.ts
test.ts(2,1): error TS2322: Type '"hello, world"' is not assignable to type 'number'.   

●基本的な演算子

●基本的な制御構造

●配列

リスト : 配列の使用例

let ary = [1, 2, 3, 4, 5, 6];
let ary1: number[];
let ary2: string[];
ary1 = ary;
// ary2 = ary; コンパイルエラー
console.log(ary[0]);
console.log(ary[5]);
let ary3 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
console.log(ary3[0][0]);
console.log(ary3[2][2]);
1
6
1
9

●タプル

リスト : タプルの使用例

let a: [number, string, boolean]; // タプル
let b = [10, "bar", true];        // 配列 (要素の型が number | string | boolean)
a = [1, "foo", false];
// b = a;    コンパイルエラー (b はタプルではなく配列)
console.log(a[0]);
console.log(a[1]);
console.log(a[2]);
// 代入するときデータ型が異なるとコンパイルエラー
a[0] = 0;    
a[1] = "bar";
a[2] = true;
console.log(a);
let [x, y, z] = a;    // 分割代入も可能
console.log(x);
console.log(y);
console.log(z);
// b はタプルではないので、異なるデータ型を代入できる
b[0] = "oops";    
b[1] = false;
b[2] = 123;
console.log(b);
1
foo
false
[ 0, 'bar', true ]
0
bar
true
[ 'oops', false, 123 ]

●列挙型

リスト : 列挙型の簡単な使用例

enum Fruit {Apple, Orange, Grape}

console.log(Fruit.Apple);
console.log(Fruit.Orange);
console.log(Fruit.Grape);
console.log(Fruit[0]);
console.log(Fruit[1]);
console.log(Fruit[2]);

// 値段表 (連想リスト)
const priceData: [Fruit, number][] = [[Fruit.Apple, 100], [Fruit.Orange, 150], [Fruit.Grape, 200]];

// 値を求める
function getPrice(fruit: Fruit): number {
    for (let [x, p] of priceData) {
        if (x == fruit) return p;
    }
    return 0;
}

console.log(getPrice(Fruit.Apple));
console.log(getPrice(Fruit.Orange));
console.log(getPrice(Fruit.Grape));
0
1
2
Apple
Orange
Grape
100
150
200

●関数

リスト : 関数の簡単な使用例

// 階乗 (再帰)
function fact(n: number): number {
    if (n == 0) return 1;
    return n * fact(n - 1);
}

for (let i = 0; i < 15; i++) console.log(fact(i));

// フィボナッチ数 (末尾再帰)
function fibo(n: number, a = 0, b = 1): number {
    if (n == 0) return a;
    return fibo(n - 1, b, a + b);
}

for (let i = 0; i < 15; i++) console.log(fibo(i));

// 高階関数
const a = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(a.map(x => x * x));
console.log(a.filter(x => x % 2 == 0));
console.log(a.reduce((a, x) => a + x));
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
[ 1, 4, 9, 16, 25, 36, 49, 64 ]
[ 2, 4, 6, 8 ]
36

●クラス

リスト : 簡単な例題 (point.ts)

class Point {
    // コンストラクタ
    constructor(private x: number, private y: number) { }

    // メソッド
    distance(p: Point): number {
        const dx = this.x - p.x;
        const dy = this.y - p.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
}

class Point3D {
    // コンストラクタ
    constructor(private x: number, private y: number, private z: number) { }

    // メソッド
    distance(p: Point3D): number {
        const dx = this.x - p.x;
        const dy = this.y - p.y;
        const dz = this.z - p.z;
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }
}

const p0 = new Point(0, 0);
const p1 = new Point(10, 10);
const p2 = new Point3D(0, 0, 0);
const p3 = new Point3D(10, 10, 10);
console.log(p0.distance(p1));
console.log(p2.distance(p3));
14.142135623730951
17.320508075688775

●get/set アクセサ

リスト : get/set アクセサの使用例

class Foo {
    // コンストラクタ
    constructor(private _baz: string, private _bar: number) { }

    // メソッド
    get bar(): number { return this._bar; }
    set bar(x: number) { this._bar = x; }
    get baz(): string { return this._baz; }
    set baz(s: string) { this._baz = s; }
}

const foo = new Foo("abc", 123);
console.log(foo.bar);
console.log(foo.baz);
console.log(foo);
foo.bar = 456;
foo.baz = "def";
console.log(foo);

●継承

リスト : 継承の簡単なサンプル

class Bar {
    constructor(private _a: number, private _b: number) { }
    get a(): number { return this._a; }
    get b(): number { return this._b; }

    // 合計値を求める
    sum(): number { return this.a + this.b; }
}

class Baz extends Bar {
    constructor(a: number, b: number, private _c: number) {
        super(a, b);
    }
    get c(): number { return this._c; }

    // 合計値を求める
    sum(): number {
        return super.sum() + this.c;
    }
}

const bar = new Bar(1, 2);
const baz = new Baz(10, 20, 30);

console.log(bar.a);
console.log(bar.b);
console.log(baz.a);
console.log(baz.b);
console.log(baz.c);
console.log(bar.sum());
console.log(baz.sum());
1
2
10
20
30
3
60

●抽象クラス

リスト : 抽象クラスの簡単な例題

// 図形クラス
abstract class Figure {
    abstract kindOf(): string;
    abstract area(): number;
    print(): void {
        console.log(`${this.kindOf()}: area = ${this.area()}`)
    }
}

// 三角形
class Triangle extends Figure {
    constructor(private altitude: number, private baseLine: number) {
        super();
    }
    kindOf(): string { return "Triangle"; }
    area(): number { return this.altitude * this.baseLine / 2; }
}

// 四角形
class Rectangle extends Figure {
    constructor(private width: number, private height: number) {
        super();
    }
    kindOf(): string { return "Rectangle"; }
    area(): number { return this.width * this.height; }
}

// 円
class Circle extends Figure {
    constructor(private radius: number) {
        super();
    }
    kindOf(): string { return "Circle"; }
    area(): number { return Math.PI * this.radius * this.radius; }
}

const a = new Triangle(2, 2);
const b = new Rectangle(2, 2);
const c = new Circle(2);

a.print();
b.print();
c.print();

const table = [new Triangle(3, 3), new Rectangle(3, 3), new Circle(3)];

table.forEach(x => x.print());
Triangle: area = 2
Rectangle: area = 4
Circle: area = 12.566370614359172
Triangle: area = 4.5
Rectangle: area = 9
Circle: area = 28.274333882308138

●インターフェース

リスト : インターフェースの簡単な使用例

interface FooI {
    bar: number;
    baz(): string;
    oops?: string; 
}

class FooC implements FooI {
    constructor(public bar: number) { }
    baz(): string { return `bar = ${this.bar}`}
}

const d = new FooC(123);
console.log(d.baz());
console.log(d);
let e: FooI;
e = d;  // 代入できる (いわゆるアップキャスト)
console.log(d);
bar = 123
FooC { bar: 123 }
FooC { bar: 123 }
リスト : 図形クラスを interface で書き直す

// インターフェースの定義
interface Figure {
    kindOf(): string;
    area(): number;
    print(): void;
}

// 三角形
class Triangle implements Figure {
    constructor(private altitude: number, private baseLine: number) { }
    kindOf(): string { return "Triangle"; }
    area(): number { return this.altitude * this.baseLine / 2; }
    print(): void {
        console.log(`${this.kindOf()}: area = ${this.area()}`);
    }
}

// 四角形
class Rectangle implements Figure {
    constructor(private width: number, private height: number) {  }
    kindOf(): string { return "Rectangle"; }
    area(): number { return this.width * this.height; }
    print(): void {
        console.log(`${this.kindOf()}: area = ${this.area()}`);
    }
}

// 円
class Circle implements Figure {
    constructor(private radius: number) { }
    kindOf(): string { return "Circle"; }
    area(): number { return Math.PI * this.radius * this.radius; }
    print(): void {
        console.log(`${this.kindOf()}: area = ${this.area()}`);
    }
}

const a = new Triangle(2, 2);
const b = new Rectangle(2, 2);
const c = new Circle(2);

a.print();
b.print();
c.print();

const table = [new Triangle(3, 3), new Rectangle(3, 3), new Circle(3)];

table.forEach(x => x.print());

●ジェネリック

リスト : ジェネリックの簡単な使用例

class FooG<T> {
    constructor(private _x: T) {}
    get x(): T { return this._x;}
}

// 組
class Pair <T, U> {
    constructor(private _fst: T, private _snd: U) { }
    get fst(): T { return this._fst; }
    get snd(): U { return this._snd; }
}

const foo1 = new FooG(123),
      foo2 = new FooG("hello, world");
console.log(foo1.x);
console.log(foo2.x);

const pair1 = new Pair(1, "foo");
console.log(pair1.fst);
console.log(pair1.snd);

const pair2 = new Pair(foo1, foo2);
// const pair2 = new Pair<FooG<number>, FooG<string>>(foo1, foo2); と同じ
console.log(pair2.fst);
console.log(pair2.snd);

// 連想リストの探索
function assoc<T, U>(key: T, table: Pair<T, U>[]): U {
    for (let p of table) {
        if (p.fst == key) return p.snd;
    }
    return null;
}

const table = [
    new Pair("foo", 123), new Pair("bar", 456), new Pair("baz", 789)
]

console.log(assoc("foo", table));
console.log(assoc("bar", table));
console.log(assoc("baz", table));
console.log(assoc("oops", table));
123
hello, world
1
foo
FooG { _x: 123 }
FooG { _x: 'hello, world' }
123
456
789
null

●オブジェクト型リテラル

リスト : オブジェクト型リテラルの使用例

let obj1: { 
    foo: number;      // プロパティシグニチャ
    bar(): string;    // メソッドシグニチャ
};
const obj2 = { foo: 123, bar() { return "hello, world"; }};
// obj1 と obj2 は同じデータ型
obj1 = obj2;
console.log(obj1.foo);
console.log(obj1.bar());

let obj3: { 
    (x: number, y: number): number;   // コールシグニチャ
 };
// let obj3: (x: number, y: number) => number; と同じ
obj3 = (x, y) => x + y;
console.log(obj3(1, 2));

class FooObj {
    constructor(private _x: number) { }
    get x(): number { return this._x; }
 }

let obj4: {
    new(x: number): FooObj;  // コンストラクタシグネチャ
};

obj4 = FooObj;
const obj5 = new obj4(123);
console.log(obj5);

// インデックスシグネチャ
let obj6: {
    [index: number]: number;   // [ ] の中の添字は数値だけ
};
obj6 = {
    1: 123,
    2: 456,
    // foo: 789  コンパイルエラー
};
console.log(obj6);

// 角カッコでの代入はエラーにならない
obj6['foo'] = '100';
console.log(obj6['foo']);
console.log(obj6);

let obj7: {
    [index: string]: number;   // [ ] の中の添字は文字列と数値だけ
};
obj7 = {
    foo: 100,
    bar: 200,
    123: 400    // 数値も OK
}
console.log(obj7);
123
hello, world
3
FooObj { _x: 123 }
{ '1': 123, '2': 456 }
100
{ '1': 123, '2': 456, foo: '100' }
{ '123': 400, foo: 100, bar: 200 }

●構造的部分型

リスト : 構造的部分型

const obj10 = { x(): number { return 123; } };

const obj11 = {
     x(): number { return this._x; },
     _x: 456
};

const obj12 = {
    x(): number { return this._x;},
    _x: 789,
    y(): string { return "hello, world"; }
};

function getX(obj: { x(): number }) {
    return obj.x();
}

// どのオブジェクトもメソッド x() を持っているので
// getX() に渡すことができる
console.log(getX(obj10));
console.log(getX(obj11));
console.log(getX(obj12));
123
456
789

●イテレータとジェネレータ

リスト : イテレータとジェネレータ

// 引数を順番に取り出す
function makeIter<T>(...args: T[]): Iterator<T> {
    let idx = 0;
    return {
        next(): IteratorResult<T> {
            if (idx == args.length) {
                return { done: true, value: undefined };
            } else {
                return { done: false, value: args[idx++] };
            }
        }
    };
}

const iter = makeIter(1,2,3,4);
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

// for ... of を使いたい場合
function makeIterable<T>(...args: T[]): IterableIterator<T> {
    let idx = 0;
    return {
        next(): IteratorResult<T> {
            if (idx == args.length) {
                return { done: true, value: undefined };
            } else {
                return { done: false, value: args[idx++] };
            }
        },
        [Symbol.iterator](): IterableIterator<T> { return this; }
    };
}

for (let x of makeIterable(1,2,3,4)) {
    console.log(x);
}

// function* を使うともっと簡単
function* makeGen<T>(...args: T[]): IterableIterator<T> {
    yield* args;
}

for (let x of makeGen(5,6,7,8)) {
    console.log(x);
}
{ done: false, value: 1 }
{ done: false, value: 2 }
{ done: false, value: 3 }
{ done: false, value: 4 }
{ done: true, value: undefined }
1
2
3
4
5
6
7
8

●セットとマップ

リスト : セットとマップの簡単な使用例

const s1 = new Set<number>();
[1,3,5,7,9].forEach(x => s1.add(x));
console.log(s1);
console.log(s1.has(5));
console.log(s1.has(6));

const m1 = new Map<string, number>();
m1.set("foo", 123);
m1.set("bar", 456);
m1.set("baz", 789);
console.log(m1);
console.log(m1.get("bar"));
console.log(m1.get("oops"));
Set { 1, 3, 5, 7, 9 }
true
false
Map { 'foo' => 123, 'bar' => 456, 'baz' => 789 }
456
undefined

Copyright (C) 2017 Makoto Hiroi
All rights reserved.

[ Home | Light | JavaScript | TypeScript ]