typeというキーワードで型が作れますよね。インターフェースとの使い分けがいまいちよくわからないんですが。typeキーワードは、基本的には他の型のエイリアスを作るだけなんです。同様のことをインターフェースで実現できる場合は、インターフェースの利用が推奨されています。tslintで、typeの代わりにインターフェースを使うように強制することもできますね。Type)を定義する場合はtypeキーワードを使う必要があります。深い話になってきましたね。文字列リテラル型というのは、型に文字列リテラルを指定できるっていうTypeScript独自の機能ですね。Typeというのもあります。この機能を使うと、プロパティが動的に変化するオブジェクトの場合も、コンパイラで可能な限り型チェックできるようになります。以下の例では、キーは文字列、その値も文字列となる動的な型を定義しています。type]のように書くのがポイントですね。ほかにtypeを使用する必要があるのは、型の合成を行う場合です。Typeと言って、型の積集合を作る機能です。簡単に言えば、二つの型を混ぜ合わせる機能ですね。使用方法は簡単で、二つ以上の型を’&’でつなぐだけです。B;クラス、インターフェース、type宣言で作成した型など、様々な型を混ぜ合わせて新しい型を作ることが可能です。こんな機能あったんですね、知りませんでした。Typeといって、どちらかの型を排他的に持つ型を作ることもできます。こちらは、二つ以上の型を’|’でつなぐことで作ることができます。Typeは使ったことあります。いろんな型を受け取る関数を作るときとかに便利ですよね。ジェネリクスは「総称型」とも呼ばれ、型をパラメータ化できるというものです。総称型は、パラメータ化された型を外から与えられて、初めて実際の型が決まります。MyArray<number>();上の例で言うと「T」がパラメータ化された型ですね。MyArray<number>()のところで、number型を与えられています。パラメータ化される型に「ある型を親として持っていなくてはならない」などの制約を設けることもできます。その場合はextendsキーワードを用いて、以下のように型パラメータを記述します。ジェネリクスはTypeScript固有の機能というわけではないですよね。C++やJava、C#など、静的型付けの言語はジェネリクスを備えるものも多い。Guardは、型をインテリジェントに絞り込む機能です。以下のようなコードでは、instanceofやtypeofで判定しているif文のブロック内では、変数をその型だと見なして、キャストせずに利用することができます。あ、これは知ってますし、よく使いますね。最初この機能を知った時、最近のコンパイラは頭がいいなあ、と感動しました。Guardは、開発者が拡張することもできるんですよ。以下のような関数を用意しておくと、if文の条件式でこの関数を用いた時、そのブロック内では変数がstring型として扱われます。<型名>と指定するんですね。Guardを自作できるとは知りませんでした。neverという型もあります。neverは決して到達できない、何も代入することのできない型を表します。エラーをthrowする関数の戻り値型をnever型にしたり、到達することのないコードブロックの変数型がneverになったりします。なんとなく分かる気はしますが、何の役に立つんですか?これ。確かにわかりづらいですよね。voidとの違いがわからないという話もよく出ます。以下の例を見るとわかりやすいんじゃないかと思います。後者の特徴(到達することのないコードブロック内での変数型がneverになる)をうまく使うと、より型安全なコードを書くのに役立ったりします。到達しないはずのコード位置で変数をneverとして扱うコードを書いておけば、コンパイラがコードの到達可能性をチェックしてくれるということですね。2.1から入った、比較的新しくてなかなか面白い機能です。この機能を使うと、他の型を元にして、型を動的に定義することができるんです。深い話になってきたな...。「あるインターフェースがあって、そのプロパティすべてをreadonlyにした新しい型を作りたい」といった場合を考えてください。ああ、そういうのはありそうですね。いう場合TypeScriptでどうやるかというと、まず元のインターフェースのプロパティ名を全て含む型を作るんです。keyofというキーワードを使うと、型のプロパティ名を全て含む文字列リテラル型を取得できます。以下のように書くことで、全てのプロパティをreadonlyにした型を作ることができます。・全てのプロパティの先頭にreadonlyが付与されることがポイントになります。元の型のプロパティをループしながら、新しい型を作るような感覚ですね。コンパイル時に、動的な処理を行って型を作っていっているような感覚ですね。したテクニックを使うと、全部のプロパティをPromiseでラップしたり、null許容型にしたりした新しい型を作るのも容易に行なえます。いやー、TypeScriptは型の定義方法がとても柔軟ですね...。深いところまできた気がしますね。ぼく普段TypeScript使ってるのに、知らないこともたくさんありました。いや、実はこのスライドで紹介してるのは、私が重要だと判断したところだけで、TypeScriptにはまだまだ機能があります(笑)。ええっ、もう頭がいっぱいいっぱいなんですが...。ここからは、TypeScriptに今後搭載される予定の機能とかロードマップ、議論されている話について伺っていきたいと思います。はい、では一つ目の話題は「Variance」です。これは、「ある型と別の型が相互代入可能か」っていう関係性についてのお話です。Baseというクラスと、それを継承しているクラスがあったとして、それらの配列と、それらを仮引数にとる関数について、それぞれ相互代入可能かを考えてみましょう。3;}以下は配列の場合です。親クラス型の配列(baseAttr)に、子クラス型の配列(derivedArr)は代入できます。これを共変の関係といいます。親クラス型の配列変数に、子クラスの配列を代入するというのはよくあるシチュエーションです。配列が共変であるというのは、実用上の利便性が高いんです。baseArr;しかし、これらの型を仮引数に取る関数について考えてみましょう。この場合、どちらの方向の代入も成り立ってしまうのです。これを双変の関係といいます。Another())つまりTypeScriptは、配列については共変、関数については双変としているわけですが、これは実は型システムに矛盾を生じます(※)。した矛盾はあえて受け入れたものであり、その理由は「配列の共変性」による利便性、実用性を重んじてのことでした(※)。実は、関数についての双変性をやめ、C#のように共変/反変をin/outパラメータで指定できるようにしてはどうか...という議論が持ち上がっています。...む、むずかしい...※ここは、議論が詳細過ぎるため編集上割愛しました。型システムが健全性を諦めているかというna-o-ysさんの記事が参考になると思います。Symbol型ですね。これはconstな変数やreadonlyなプロパティを、クラスやインターフェース、typeのプロパティ名に使うことができます。namesを型宣言時に使えるような感じですね。ちなみに、ECMAScriptにprotocolという機能を追加するって提案があります。Symbol型とはあまり関連はありませんが、プロパティ名にシンボルを指定するというところから思い出しました。インターフェースに近くて、implementsするクラスに実装を強要するものです。複数のプロトコルをimplementsすることもできます。型の概念が薄いJavaScriptにも、ついにインターフェース相当のものが!でも、それならinterfaceってキーワード使えばいいのに...。目的は似通っていますが、プロトコルは「シンボルの集合」という形で表現されたり、デフォルト実装を提供できたりと、結構違いはあります。※青野さんがその後書いてらっしゃったブログ記事からの引用ですが、プロトコルは以下のように宣言/実装するそうです。ほかには、可変長型をサポートすることも予定されています。可変長型というのは、言ってみれば配列要素の型をまとめて保持する型です。...Tのように記述することで可変長型を表すことができます。number}]可変長型のサポートにより、可変長引数を取る関数で引数の型を利用できたり、可変長の型パラメータを実装できます。可変長型はタプルとも互換性があります。こんなアイデアまであるんですね...ぼくなんか、TypeScriptでタプル使えるの今まで知りませんでした(笑)。セッション内容の、型に関するお話だけでも、すごいボリュームになりました。Typingなどを許容しよう(※)という話もありますが...まだ実装の同意は取れてない状態ですね。お腹いっぱいです(笑)。