検索
ニュース

プログラミング言語「TypeScript 4.5」をMicrosoftが公開機能を大幅に拡充

Microsoftはオープンソースのプログラミング言語の最新版「TypeScript 4.5」を公開した。「Awaited」型の導入など、多くの機能が追加、強化され、パフォーマンスも向上している。

Share
Tweet
LINE
Hatena

 Microsoftは2021年11月17日(米国時間)、オープンソースのプログラミング言語の最新版「TypeScript 4.5」を公開した。「Awaited」型の導入など、多くの新しい機能や改善があり、生産性やパフォーマンスも向上している。

 TypeScriptは静的型付けができる言語であり、JavaScriptのスーパーセットだ。ECMA規格に従った最新のJavaScriptの機能を、古いWebブラウザやランタイムが扱えるようにコンパイルすることもできる。

 NuGetを使うか、次のコマンドラインのように、npmを使ってTypeScript 4.5をインストールできる。

npm install typescript

 TypeScript 4.5は「Visual Studio 2019」と「Visual Studio 2017」のエディタでサポートされており、「Visual Studio Code」(以下、VS Code)、「Sublime Text 3」でも利用できる。TypeScript 4.5の主な特徴は次の通り。

「Awaited」型の導入と「Promise」の改良

 新しいユーティリティー型「Awaited」が導入された。Awaitedは、「async」関数の「await」や、「Promise」の「.then()」メソッド(Promiseを再帰的にアンラップする方法)のような操作のモデル化を目的としている。

// A = string
type A = Awaited<Promise<string>>;
// B = number
type B = Awaited<Promise<Promise<number>>>;
// C = boolean | number
type C = Awaited<boolean | Promise<number>>;

 加えて、「Promise.all」レバレッジが特定の機能とAwaitedを組み合わせ、より良い推論結果を提供するようになった。

「node_modules」からの「lib」のサポート

 特定のビルトインlibを、「@types/」サポートの仕組みと似た方法でオーバーライドする方法が導入された。どのlibファイルを含めるべきなのかを判断する際、TypeScriptはまず、「node_modules」のスコープされた「@typescript/lib-*」パッケージを探す。例えば、「dom」をlibのオプションとして含めるとき、TypeScriptは、「node_modules/@typescript/lib-dom」の型が使用可能な場合、それを使用する。

 次に、パッケージマネジャーを使って、所定のlibに取って代わる特定のパッケージをインストールできる。例えば、TypeScriptは現在、@types/webでDOM APIのさまざまなバージョンを公開している。プロジェクトを特定のバージョンのDOM APIにロックしたい場合、次のコードを「package.json」に追加すればよい。

{
 "dependencies": {
    "@typescript/lib-dom": "npm:@types/web"
  }
}

 TypeScript 4.5から、TypeScriptを更新すると、依存関係マネジャーのロックファイルが、同じバージョンのDOMタイプが使われることを保証するようになった。このため、タイプを自分のペースで更新できる。

判別式としてのテンプレート文字列型に対応

 テンプレート文字列型を持つ値を絞り込めるようになり、テンプレート文字列型を判別式として認識するようになった。

モジュール設定「--module es2022」に対応

 新しいモジュール設定「es2022」をサポートするようになった。「--module es2022」の主な機能はトップレベルawaitであり、「async」関数の外部でawaitを使用できる。

条件型における末尾再帰の除去

 条件型で一部の末尾再帰が除去された。条件型の1つの分岐が他の条件型である場合、中間のインスタンス化を回避できる。

 なお、次の型は最適化されない。条件型をユニオンに追加し、条件型の結果を使用しているからだ。

type GetChars<S> =
    S extends `${infer Char}${infer Rest}` ? Char | GetChars<Rest> : never;

 末尾再帰を使用したい場合は、末尾再帰関数を使う場合と同様に“アキュムレーター”の型パラメーターを取るヘルパーを導入する。

type GetChars<S> = GetCharsHelper<S, never>;
type GetCharsHelper<S, Acc> =
    S extends `${infer Char}${infer Rest}` ? GetCharsHelper<Rest, Char | Acc> : Acc;

インポート削除の無効化が可能に

 従来のTypeScriptは次のようなコードにおいて、インポートが使用されていないと判断すると、既定でインポートを削除する。

import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");

 TypeScript 4.5では、「--preserveValueImports」という新しいフラグを有効にすることで、JavaScript出力からインポートされた値を削除しないようにできる。上の例のように「eval」を使うケースはめったにないが、この新機能は、Svelteを使う場合にも役立つ。

<!-- A .svelte File -->
<script>
import { someFunc } from "./some-module.js";
</script>
<button on:click={someFunc}>Click me!</button>

 この他、Vue.jsで「<script setup>」機能を使う場合にも役立つ。

<!-- A .vue File -->
<script setup>
import { someFunc } from "./some-module.js";
</script>
<button @click="someFunc">Click me!</button>

インポート名に「type」修飾子が付けられる

 --preserveValueImportsと「--isolatedModules」を組み合わせる場合、どんなときにインポートを正当に削除できるのかを示す方法が必要になる。これまでのTypeScriptでは、「import type」を使っていた。

import type { BaseType } from "./some-module.js";
import { someFunc } from "./some-module.js";
export class Thing implements BaseType {
    // ...
}

 だが、同じモジュールについて2つの重要な文を記述するのは避けたい。そこでTypeScript 4.5では、個々の名前付きインポートに「type」修飾子を付けられるようになった。

import { someFunc, type BaseType } from "./some-module.js";
export class Thing implements BaseType {
    someMethod() {
        someFunc();
    }
}

プライベートフィールドの存在チェックが可能に

 TypeScript 4.5はオブジェクトがプライベートフィールドを持つかどうかのチェックに関するECMAScriptの提案をサポートした。「#private」フィールドメンバーを持つクラスを作成し、「in」演算子を使って、他のオブジェクトが同じフィールドを持っているかどうかをチェックできるようになった。

class Person {
    #name: string;
    constructor(name: string) {
        this.#name = name;
    }
    equals(other: unknown) {
        return other &&
            typeof other === "object" &&
            #name in other && // <- this is new!
            this.#name === other.#name;
    }
}

インポートアサーションに対応

 TypeScript 4.5はインポートアサーションに関するECMAScriptの提案もサポートした。これはインポートが期待されたフォーマットを持つことを、ランタイムが確認するために使用する構文だ。

import obj from "./something.json" assert { type: "json" };

JSDocの「const」アサーションと既定の型引数を改善

 TypeScriptでは、リテラルの後で「as const」を書くことで、正確な不変の型が得られる。

// type is { prop: string }
let a = { prop: "hello" };
// type is { readonly prop: "hello" }
let b = { prop: "hello" } as const;

 JavaScriptファイルでJSDocの型アサーションを使って、同じことができるようになった。

// type is { prop: string }
let a = { prop: "hello" };
// type is { readonly prop: "hello" }
let b = /** @type {const} */ ({ prop: "hello" });

 なお、JSDocの型アサーションコメントは、「/** @type {TheTypeWeWant}」で始まり、カッコで囲まれた式がこれに続く。

/** @type {TheTypeWeWant} */` (someExpression)

 TypeScript 4.5では、JSDocに既定の型引数も追加された。これは、TypeScriptのtype宣言が、JavaScriptで「@typedef」として書き換えられることを意味する。

type Foo<T extends string | number = number> = { prop: T };
TypeScriptのtype宣言
/**
 * @template {string | number} [T=number]
 * @typedef Foo
 * @property prop {T}
 */
// or
/**
 * @template {string | number} [T=number]
 * @typedef {{ prop: T }} Foo
 */
JavaScriptで書き換えられたコード

「realpathSync.native」による読み込みの高速化

 TypeScript 4.5では、全てのOSでNode.jsの「realpathSync.native」関数を利用するようになった。

 これまでこの関数はLinuxでのみ使用されてきた。TypeScript 4.5では、Node.jsの最近のバージョンを実行していれば、一般に大文字と小文字を区別しないOS(WindowsやmacOSのような)でも、コンパイラがこの関数を使用するようになった。これにより、Windows上の特定のコードベースでは、プロジェクトの読み込みが5〜13%高速になった。

Copyright © ITmedia, Inc. All Rights Reserved.

ページトップに戻る