
TypeScript4.1(beta)で追加された新機能とは?
2021.12.20
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」は、テンプレートリテラルを使って型を定義できる機能です。
具体的には、以下のように、変数展開をする感じです。
1 2 3 4 5 6 7 8 | type TypeScript = 'TypeScript' type HelloTs = `Hello, ${TypeScript}` // => type HelloTs = 'Hello, TypeScript' type Join<T extends string, S extends string> = `${T}, ${S}` type HelloTs2 = Join<'Hello', 'TypeScript'> // => type HelloTs2 = 'Hello, TypeScript' |
全ての組み合わせの型が作成可能
さらに、Union Type を引数にすると、こんなこともできちゃいます!
1 2 3 | type Hello<T extends string> = `Hello, ${T}`; type T1 = Hello<'foo' | 'bar' | 'baz'>; // => type T1 = 'Hello, foo' | 'Hello, bar' | 'Hello baz'; |
では、Union Type を2つ定義した場合はどうなるのでしょうか?
1 | type T3 = `${'top' | 'bottom'}-${'left' | 'right'}`; |
結果を見てみましょう!
1 | type 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 は、以下のように記述していました。
1 2 3 | type Partial<T> = { [K in keyof T]?: T[K] }; |
これでは、プロパティ名は T 型のキー名でしか生成することができません。
4.1の記述
TypeScript 4.1からは「Key Remapping in Mapped Types」を使えば、自由にプロパティ名を設定することができます。
プロパティ名に任意の名前をつける書き方は、以下のように記述してください。
1 2 3 | type MappedTypeNewKeys<T> = { [K in keyof T as NewKeyType]: T[K] } |
NewKeyType の部分に、自分の指定したいプロパティ名を設定できます。
具体的には、以下のような使い方をします。
1 2 3 4 5 6 7 8 9 10 11 | type Getters<T> = { [K in keyof T as `get${capitalize K}`]: () => T[K] }; interface Person { name: string; age: number; location: string; } type 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以前では、出来ないわけではなかったものの、記述がかなり複雑になってしまうため、自然な記述ができるようになったのはありがたいですね。
1 | type ElementType<T> = T extends ReadonlyArray<infer U> ? ElementType<U> : T; |
この例では、T が読み込み専用の配列なら、その中身の型を取り出すようになっています。
ネストが深い配列も型安全に処理できる
入れ子構造になっている配列を、フラットにするような関数の型も表現できます。
1 2 3 4 5 6 7 | function deepFlatten<T extends readonly unknown[]>(x: T): ElementType<T>[] { throw "ここに実装を書きます"; } deepFlatten([1, 2, 3]); deepFlatten([[1], [2, 3]]); deepFlatten([[1], [[2]], [[[3]]]]); |
この deepFlatten 関数は、引数 [1, 2, 3] 、 [[1], [2, 3]] 、 [1], [[2]], [[[3]]]] のどれをとっても、返り値は number 型になります。
では、deepFlatten 関数の型は一体どうなっているのでしょうか?
それぞれの引数で、具体的に関数の型がどうなっているのかを見てみましょう。
1 2 3 4 | function deepFlatten<number[]>(x: number[]): number[] { throw "ここに実装を書きます"; } deepFlatten([1, 2, 3]); |
1 2 3 4 | function deepFlatten<number[][]>(x: number[][]): number[] { throw "ここに実装を書きます"; } deepFlatten([[1], [2, 3]]); |
1 2 3 4 | function deepFlatten<number[] | number[][] | number[][][][]>(x: number[] | number[][] | number[][][][]): number[] { throw "ここに実装を書きます"; } deepFlatten([[1], [[2]], [[[3]]]]); |
このように、どれだけネストの深い配列がきたとしても、再帰的な型定義をすれば、型安全に処理することができるのです。
まだまだある、その他の新機能
以上、特に注目の高い新機能を見てきましたが、TypeScript 4.1にはまだまだ便利な新機能が追加されています。
--noUncheckedIndexedAccess
「--noUncheckedIndexedAccess」は、TypeScript 4.1のコンパイラオプションです。
undefined になりうる全てのインデックスアクセスに対して、エラーを発生させます。
例えば、以下のコードでもエラーが発生します。
1 2 3 4 5 6 7 | function showLines(strs: string[]) { for (let i = 0; i < strs.length; i++) { console.log(strs[i].toLowerCase()); // ~~~~~~~ // strs[i]はundefinedになりうるので、エラー } } |
この場合、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 3 4 5 6 7 8 | { "compilerOptions": { "module": "esnext", "target": "es2015", "jsx": "react-jsx", "strict": true } } |
さいごに
この記事では、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の新機能を知って、より深い型の世界に浸っていきましょう!
こちらの記事もオススメ!
書いた人はこんな人

- 「好きを仕事にするエンジニア集団」の(株)ライトコードです!
ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。
システム開発依頼・お見積もり大歓迎!
また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です!
インターンや新卒採用も行っております。
以下よりご応募をお待ちしております!
https://rightcode.co.jp/recruit
ライトコードの日常12月 1, 2023ライトコードクエスト〜東京オフィス歴史編〜
ITエンタメ10月 13, 2023Netflixの成功はレコメンドエンジン?
ライトコードの日常8月 30, 2023退職者の最終出社日に密着してみた!
ITエンタメ8月 3, 2023世界初の量産型ポータブルコンピュータを開発したのに倒産!?アダム・オズボーン