RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

TypeScript5.4の新機能をピックアップ

はじめに

こんにちは。フロントエンド開発課に所属している新卒1年目のm_you_sanと申します。
3月6日にTypeScript5.4がリリースされました。
そこで、今回は個人的に気になった機能についてピックアップして紹介したいと思います。

型の絞り込み

関数クロージャ内の型の絞り込みの挙動が少し変わりました。

以下のgetUrlsでは、まず始めにtypeof演算子を使用して、第一引数のurlがstring型かどうかを確認しています。
string型であった場合、URLインスタンスを生成します。
その後、map関数内でURLのプロパティであるsearchParamsを使用しています。

function getUrls(url: string | URL, names: string[]) {
    if (typeof url === "string") {
        url = new URL(url);
    }

    return names.map(name => {
        url.searchParams.set("name", name);
        return url.toString();
    });
}

このとき従来の挙動の場合、map関数のクロージャ内では、if (typeof url === "string")...内で絞り込んだ型情報が保持されず、urlがstringとURLのユニオン型になるため、searchParamsの部分でエラーが発生します。
そのため、map関数クロージャ内で再度、型情報を絞り込む必要がありました。

  return names.map(name => {
    // もう一度型情報を絞り込む
    if (typeof url === "string") return;
    url.searchParams.set("name", name);
      return url.toString();
  });

しかし、5.4からクロージャ内で型情報が保持されるようになったため、上記のようにわざわざもう一度型情報を絞り込む必要がなくなりました。
ただし、以下のようにネストされた関数内で、型情報を絞り込んだ変数が代入された場合は、型情報が保持されなくなります。

function printValueLater(value: string | undefined) {
    if (value === undefined) {
        value = "missing!";
    }

    setTimeout(() => {
        value = value;
    }, 500);


    setTimeout(() => {
        // エラーが発生する
        console.log(value.toUpperCase());
    }, 1000);
}

また、functionを使って関数宣言をした場合、ホイスティングができるため、型情報を保持することができません。
以下のコードの場合、toUpperCaseFnif (value === undefined)...より前に呼び出すことが可能なので、valueをstringに絞り込むことができません。
アロー関数の場合は、ホイスティングができないので、正常に型情報を絞り込むことが可能です。

function printValueLater(value: string | undefined) {
    // ここで呼び出すことが可能
    // toUpperCaseFn();

    if (value === undefined) {
        value = "missing!";
    }

    function toUpperCaseFn() {
      // エラーが発生する
      console.log(value.toUpperCase());
    }

    // エラーは発生しない
    const toUpperCaseFn2 = () => console.log(value.toUpperCase());
}

NoInfer

NoInferは新しく追加されたユーティリティ型で、不要な型推論をブロックすることができます。
以下のコードでは、colorsの配列要素の一部がdefaultColorの型になるようにしています。
しかし、配列の要素にないものをdefaultColorに設定しても、型推論が効いてしまうため、型エラーが発生しません。
この場合、defaultColorからジェネリクスCを推論させないようにする必要があります。

function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
    // ...
}

createStreetLight(["red", "yellow", "green"], "blue");

createStreetLightの型情報

そこで、NoInferを使用すると型推論がブロックされ、defaultColorcolorsの配列要素の一部であることをチェックできるようになります。

function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
    // ...
}

// blueは配列の要素に存在しないため、エラーが発生
createStreetLight(["red", "yellow", "green"], "blue");

createStreetLightの型情報

まとめ

今回は、TypeScript5.4の新機能から個人的に気になったものを紹介しました。
クロージャ内の型情報の保持は、今後開発を進める中で役立つ場面が出てくるのではないかと思いました。
5.4の機能について、更に詳しく知りたい方は、リリースノートをご覧ください。

参考資料

devblogs.microsoft.com

Copyright © RAKUS Co., Ltd. All rights reserved.