TypeScript は JavaScript の仕様 ECMAScript2015 (ES2015) のスーパーセットです。ES2015 は拙作のページ お気楽 ECMAScript2015 超入門 で説明しています。本文中の [ES2015] は拙作のページへのリンクを表しています。よろしければお読みくださいませ。
let num: number; // 数 let str: string; // 文字列 let done: boolean; // 真偽値
let num = 1234; // 数 let str = "hello, world"; // 文字列 let done = true; // 真偽値
リスト : データ型のチェック 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 名前 {name0, name1, name2, name3, name4, name5, ... }
リスト : 列挙型の簡単な使用例 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 関数名(仮引数名: データ型, ...): 返り値の型 { 処理; ...; return 返り値; }
リスト : 関数の簡単な使用例 // 階乗 (再帰) 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
リスト : クラスの簡単な使用例 class Foo { // フィールド private bar: number; private baz: string; // コンストラクタ constructor(s: string, x: number) { this.bar = x; this.baz = s; } // メソッド getBar(): number { return this.bar; } setBar(x: number): void { this.bar = x; } getBaz(): string { return this.baz; } setBaz(s: string): void { this.baz = s; } } // インスタンスの生成 const foo = new Foo("abc", 123); // メソッドでフィールドにアクセスする console.log(foo.getBar()); console.log(foo.getBaz()); console.log(foo); foo.setBar(456); foo.setBaz("def"); console.log(foo);
123 abc Foo { bar: 123, baz: 'abc' } Foo { bar: 456, baz: 'def' }
リスト : 引数プロパティ宣言の使用例 class Foo { // コンストラクタ // フィールドにコンストラクタの実引数がセットされる constructor(private baz: string, private bar: number) { } // メソッド getBar(): number { return this.bar; } setBar(x: number): void { this.bar = x; } getBaz(): string { return this.baz; } setBaz(s: string): void { this.baz = s; } }
リスト : 簡単な例題 (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 名前(): データ型 { return this.フィールド名; } アクセス修飾子 set 名前(仮引数: データ型) { this.フィールド名 = 仮引数; }
リスト : 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 className extends superClassName { ... }
リスト : 継承の簡単なサンプル 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 クラス名 { ... abstract メソッド名(仮引数: データ型, ...): データ型; ... }
リスト : 抽象クラスの簡単な例題 // 図形クラス 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 インターフェース名 extends インターフェース1, ... { フィールドの宣言; ...; メソッドの宣言; ... }
class クラス名 extends スーパークラス implements インターフェース1, ... { ... }
リスト : インターフェースの簡単な使用例 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());
関数名<T, ...>(仮引数: データ型, ...): データ型 { ... } <T, ...>(仮引数: データ型, ...): データ型 => { ... } // アロー関数 class クラス名<T, ...> extends ... implements ... { ... }
リスト : ジェネリックの簡単な使用例 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
リスト : イテレータのデータ型 interface IteratorResult<T> { done: boolean; value?: T; } interface Iterator<T> { next(value?: any): IteratorResult<T>; return?(value?: any): IteratorResult<T>; throw?(e?: any): IteratorResult<T>; } interface Iterable<T> { [Symbol.iterator](): Iterator<T>; }
リスト : ジェネレータのデータ型 interface IterableIterator<T> extends Iterator<T> { [Symbol.iterator](): IterableIterator<T>; }
リスト : イテレータとジェネレータ // 引数を順番に取り出す 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