TypeScript4.1(beta)で追加された新機能とは?
エンジニアになろう!
TypeScript4.1(beta)の新機能とは?
2020年11月に、最新バージョン「4.1」の beta 版がリリースされた TypeScript。
最新版には、以下の7機能が追加されました。
- Template string types
- Key Remapping in Mapped Types
- Recursive Conditional Types
- --noUncheckedIndexedAccess
- paths without baseUrl
- checkJs Implies allowJs
- React 17 JSX Factories
今回は、上記のうち特に注目されている3つの機能をメインに、「TypeScript 4.1」の新機能を解説していきます!
新機能1:Template string types
「Template string types」は、テンプレートリテラルを使って型を定義できる機能です。
具体的には、以下のように、変数展開をする感じです。
1type TypeScript = 'TypeScript'
2
3type HelloTs = `Hello, ${TypeScript}`
4// => type HelloTs = 'Hello, TypeScript'
5
6type Join<T extends string, S extends string> = `${T}, ${S}`
7type HelloTs2 = Join<'Hello', 'TypeScript'>
8// => type HelloTs2 = 'Hello, TypeScript'
全ての組み合わせの型が作成可能
さらに、Union Type を引数にすると、こんなこともできちゃいます!
1type Hello<T extends string> = `Hello, ${T}`;
2type T1 = Hello<'foo' | 'bar' | 'baz'>;
3// => type T1 = 'Hello, foo' | 'Hello, bar' | 'Hello baz';
では、Union Type を2つ定義した場合はどうなるのでしょうか?
1type T3 = `${'top' | 'bottom'}-${'left' | 'right'}`;
結果を見てみましょう!
1type T3 = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
ご覧のように、「Template string types」を使えば、全ての組み合わせの型を作ることができるのです。
数学の分配法則とよく似ていますね。
新機能2:Key Remapping in Mapped Types
「Key Remapping in Mapped Types」は、asキーワードに Mapped Types を使い、プロパティ名を再定義できる機能です。
4.0 以前の記述
例として、Partial の型定義をしてみましょう。
TypeScript 4.0以前の Mapped Types は、以下のように記述していました。
1type Partial<T> = {
2 [K in keyof T]?: T[K]
3};
これでは、プロパティ名は T 型のキー名でしか生成することができません。
4.1の記述
TypeScript 4.1からは「Key Remapping in Mapped Types」を使えば、自由にプロパティ名を設定することができます。
プロパティ名に任意の名前をつける書き方は、以下のように記述してください。
1type MappedTypeNewKeys<T> = {
2 [K in keyof T as NewKeyType]: T[K]
3}
NewKeyType の部分に、自分の指定したいプロパティ名を設定できます。
具体的には、以下のような使い方をします。
1type Getters<T> = {
2 [K in keyof T as `get${capitalize K}`]: () => T[K]
3};
4
5interface Person {
6 name: string;
7 age: number;
8 location: string;
9}
10
11type LazyPerson = Getters<Person>;
こちらの例では、Person 型のプロパティを全て Getter にした例です。
as を使って、Person 型プロパティ名の先頭を capitalize で大文字にしてから、そのプロパティ名の先頭に get を追加しています。
また、capitalize の他にも、以下のようなものが使用可能なので、覚えておくと良いでしょう。
- uppercase:全て大文字にする
- lowercase:全て小文字にする
- uncapitalize:先頭を小文字にする
新機能3:Recursive Conditional Types
「Recursive Conditional Types」は、再帰的に Conditional Type を宣言できるようにした機能です。
TypeScript 4.0以前では、出来ないわけではなかったものの、記述がかなり複雑になってしまうため、自然な記述ができるようになったのはありがたいですね。
1type ElementType<T> = T extends ReadonlyArray<infer U> ? ElementType<U> : T;
この例では、T が読み込み専用の配列なら、その中身の型を取り出すようになっています。
ネストが深い配列も型安全に処理できる
入れ子構造になっている配列を、フラットにするような関数の型も表現できます。
1function deepFlatten<T extends readonly unknown[]>(x: T): ElementType<T>[] {
2 throw "ここに実装を書きます";
3}
4
5deepFlatten([1, 2, 3]);
6deepFlatten([[1], [2, 3]]);
7deepFlatten([[1], [[2]], [[[3]]]]);
この deepFlatten 関数は、引数[1, 2, 3] 、[[1], [2, 3]] 、[1], [[2]], [[[3]]]] のどれをとっても、返り値は number 型になります。
では、deepFlatten 関数の型は一体どうなっているのでしょうか?
それぞれの引数で、具体的に関数の型がどうなっているのかを見てみましょう。
1function deepFlatten<number[]>(x: number[]): number[] {
2 throw "ここに実装を書きます";
3}
4deepFlatten([1, 2, 3]);
1function deepFlatten<number[][]>(x: number[][]): number[] {
2 throw "ここに実装を書きます";
3}
4deepFlatten([[1], [2, 3]]);
1function deepFlatten<number[] | number[][] | number[][][][]>(x: number[] | number[][] | number[][][][]): number[] {
2 throw "ここに実装を書きます";
3}
4deepFlatten([[1], [[2]], [[[3]]]]);
このように、どれだけネストの深い配列がきたとしても、再帰的な型定義をすれば、型安全に処理することができるのです。
まだまだある、その他の新機能
以上、特に注目の高い新機能を見てきましたが、TypeScript 4.1にはまだまだ便利な新機能が追加されています。
「--noUncheckedIndexedAccess」は、TypeScript 4.1のコンパイラオプションです。
undefined になりうる全てのインデックスアクセスに対して、エラーを発生させます。
例えば、以下のコードでもエラーが発生します。
1function showLines(strs: string[]) {
2 for (let i = 0; i < strs.length; i++) {
3 console.log(strs[i].toLowerCase());
4 // ~~~~~~~
5 // strs[i]はundefinedになりうるので、エラー
6 }
7}
この場合、for 文ではなく、forEach や for...of 構文を使えば、エラーを回避できます。
場合によってはオフにしておいた方がいいオプションなので、必要な時にだけオンにするといいでしょう(ちなみに、デフォルトではオフになっています)。
paths without baseUrl
tsconfig.json のプロパティにある「paths」に関する機能です。
paths は、モジュールなどを import する際、パスを簡略化したい時などに使われます。
この新機能では、その paths に baseUrl を指定する必要がなくなりました。
checkJs Implies allowJs
4.0以前は、JavaScript に型を導入したい時、allowJs と checkJs の2種類のオプションがありました。
TypeScript 4.1 からは、デフォルトで checkJs は allowJs を指すようになります。
React 17 JSX Factories
React 17における jsxs・jsx のファクトリ関数をサポートします。
tsconfig.json の「compilerOptions」に、「react-jsx」のように指定すれば使えるようになります。
1{
2 "compilerOptions": {
3 "module": "esnext",
4 "target": "es2015",
5 "jsx": "react-jsx",
6 "strict": true
7 }
8}
さいごに
この記事では、TypeScript 4.1の新機能をご紹介しました。
「Template string types」のような手軽に使えて柔軟性が高いものから、「Recursive Conditional Types」のような再帰的に型を定義できるものまで、知ってみると面白いものばかりです。
また、新機能を使ったこんな興味深いサイトもあるので、ぜひ参考にしてみてくださいね。
【TypeScript 型パズルで作るmini interpreter】
https://medium.com/@Quramy/ネタ-typescript-型パズルで作るmini-interpreter-f21854cf3189
【TS 4.1 の機能で雑に型の足し算・引き算を作る】
https://www.pg-fl.jp/program/tips/ts_typecalc.htm
TypeScript 4.1の新機能を知って、より深い型の世界に浸っていきましょう!
こちらの記事もオススメ!
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit