# 速習Typescript Javascriptに続いて、Typescriptの読み書きを学びましょう。プログラムを動かしながら、サンプルを中心に理解を進めます。 # Typescriptとは Microsoftにより開発され、メンテナンスされている、フリーでオープンソースのプログラミング言語です。 TypeScriptはJavaScriptに対して、省略も可能な静的型付けとクラスベースオブジェクト指向を加えた厳密なスーパーセットとなっています。つまり、先程学んだJavascriptで記述したプログラムは、すべてTypescriptとして動きます。 # 実行環境 早速Typescriptのプログラムを動かしてみましょう。Visual Studio Codeでc:\Users\public\project\vue\moneta\tools\sandbox.tsを開いて下さい(Typescriptの拡張子は.tsです) 内容をすべて消去して、以下の内容を入力し、Javascriptの時と同じようにCtrl+Alt+Nで実行しましょう。 ```typescript= console.log('hello typescript'); // output hello typescript ``` # 型アノテーション 「型アノテーション」により、誤ったデータ型が使われないよう、事前に検出することができます。 ```typescript= let msg: string = 'hello typescript'; msg = 10; // output sandbox.ts(2,1): error TS2322: Type '10' is not assignable to type 'string'. ``` 数値型である10を、文字列型としてアノテーションされた変数に代入しようとしてエラーになっています。 関数の引数や返り値にアノテーションを加えることも可能です。設定済のVisual Studio Codeであれば、入力して直ちにエラー箇所が赤線になり、マウスオーバーでエラー理由が表示されます。 ```typescript= /* tslint:disable:no-console */ function padding(n: number): string { return `0000${n}`.slice(-4); } console.log(padding(1)); console.log(padding('a')); const m: number = padding(2); ``` # プリミティブ型 `string`, `number`, `boolean`, `null`, `undefined`などのプリミティブ型はすべてそのまま型として使用できます。 # オブジェクト型とinterface nameという文字列型のプロパティを持つオブジェクトの型は、以下のように記述できます。 ```typescript= const bank: { name: string } = { name: 'meguro' }; ``` 同じように見えますが、`{ name: string }`がオブジェクト型、`{ name: 'meguro' }`がオブジェクトリテラルですので、オブジェクトの値です。 同じような記載が続いて読みにくいので、オブジェクト型をインターフェースとして定義するinterface文が提供されています。 ```typescript= interface Named { name: string; } const bank: Named = { name: 'meguro' }; ``` # 配列型とジェネリクス JavaScriptでは配列はオブジェクトの一種ですが、配列の型を表すために特別な文法が用意されています。配列の型を表すためには`[]`を用います。例えば、`number[]`というのは数値の配列を表します。 ```ts= const foo: number[] = [0, 1, 2, 3]; foo.push(4); ``` また、ジェネリクスという型演算を利用して、以下のように記載することもできます。 ```ts= const foo: Array<number> = [0, 1, 2, 3]; foo.push(4); ``` # 関数型とtype宣言 `(引数の型, 引数の型) => 返り値`、として関数値の型を記述できます。 ```typescript= /* tslint:disable:no-console */ type Presenter = (n: number) => string; const good: Presenter = (n: number) => `0000${n}`.slice(-4); const bad: Presenter = (n: number) => `0000${n}`.length; // output sandbox.ts(6,7): error TS2322: Type '(n: number) => number' is not assignable to type 'Presenter'. Type 'number' is not assignable to type 'string'. ``` Presenter型として、一つの数値を引数に取り、文字列型を返す関数の型を定義しましたが、6行目の関数は数値を返すため、エラーになっています。siliceやlengthなどの組み込みのメソッドについては、返り値の型が定義されているため、すべてに型アノテーションを書かなくてもチェックが可能になっています。これを、型推論と呼んでいます。 # クラスの型 クラスを定義した場合、クラス名がそのままオブジェクトの型名として使用されます。 ```typescript= /* tslint:disable:no-console */ class Bank { public name: string; constructor(name: string) { this.name = name; } } let bank: Bank = 10; // output error TS2322: Type '10' is not assignable to type 'Bank'. ``` # ジェネリクス 複数のクラスに対して共通の処理を行う場合、多相型と呼ばれる定義を行う必要があります。型名の後ろに<型変数>と記載すると、型変数の部分を後から指定することができます。 ```ts= /* tslint:disable */ class Bank { public bankname: string = ''; } class Branch { public branchname: string = ''; } interface DB<T> { id: number; member: T; } const goodBank: DB<Bank> = { id: 1, member: new Bank() } const goodBranch: DB<Branch> = { id: 1, member: new Branch() } const bad: DB<Branch> = { id: 1, member: new Bank() } ``` 上のコードを入力すると、19行目の型変数Branchと、memberの型がBankで不一致ですので、エラーになります。 # union型 ユーザー入力情報を保持するクラスのように、初期値ではnullとして、string型を受け付けたいような場合があります。このような場合、型演算子の「|」を使用して、以下のようにunion型として記述できます。 ```ts= /* tslint:disable */ class Bank { public name: string | null = null; } const bank = new Bank(); console.log(bank.name); bank.name = 'meguro'; console.log(bank.name); // output null meguro ``` Bankクラスのnameプロパティは、nullまたはstringのunion型として定義されているので、10行目でエラーになりません。 # Mapped Types MappedTypeという機能があり、既存の型を元に新しい型を作成することができます。詳細は省略しますが、例えばあるオブジェクトのプロパティの一部分を持つ型を以下のように定義できます。ここで、Partialは、MappedType機能により、標準ライブラリに予め定義されている型関数です。 ```typescript= /* tslint:disable */ class Bank { public name: string; public num: number; } interface partialBank { name?: string; num?: number; } const bad: Bank = { name: 'mejiro' }; const good1: Partial<Bank> = { name: 'mejiro' }; const good2: partialBank = { name: 'mejiro' }; ``` 参考までにPartialの定義を記載しますが、演習をすすめる上ではまだ理解する必要はありません。 ```typescript= type Partial<T> = {[P in keyof T]?: T[P]}; ```