• トップ
  • ブログ一覧
  • TypeScript4.1(beta)で追加された新機能とは?
  • TypeScript4.1(beta)で追加された新機能とは?

    メディアチームメディアチーム
    2020.11.21

    エンジニアになろう!

    TypeScript4.1(beta)で追加された新機能とは?

    TypeScript4.1(beta)の新機能とは?

    2020年11月に、最新バージョン「4.1」の beta 版がリリースされた TypeScript。

    最新版には、以下の7機能が追加されました。

    1. Template string types
    2. Key Remapping in Mapped Types
    3. Recursive Conditional Types
    4. --noUncheckedIndexedAccess
    5. paths without baseUrl
    6. checkJs Implies allowJs
    7. 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 の他にも、以下のようなものが使用可能なので、覚えておくと良いでしょう。

    1. uppercase:全て大文字にする
    2. lowercase:全て小文字にする
    3. 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の新機能を知って、より深い型の世界に浸っていきましょう!

    こちらの記事もオススメ!

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    メディアチーム
    メディアチーム
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background