Microsoftは、多数の新機能を提供するオープンソースプログラミング言語の最新版「TypeScript 3.7」を公開した。オプショナルチェイニングの実装やnullish coalescing演算子の導入といった改善を加えた。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Microsoftは2019年11月5日(米国時間)、オープンソースのプログラミング言語の最新版「TypeScript 3.7」を公開した。
TypeScriptは、静的型付けができる言語で、JavaScriptのスーパーセット。ECMA規格に従った最新のJavaScriptの機能を、古いWebブラウザやランタイムが扱えるようにコンパイルすることもできる。
TypeScript 3.7は、NuGetを使うか、次のコマンドラインのように、npmを使ってインストールできる。
npm install typescript
TypeScript 3.7は「Visual Studio 2019」「Visual Studio 2017」の他、「Visual Studio Code」と「Sublime Text」でも利用できる。TypeScript 3.7の主な特徴は次の通り。
TypeScriptのビルトインフォーマッターにも改良を加えた。JavaScriptの自動セミコロン挿入(ASI)ルールによって、行末のセミコロンがオプションとなっている場所で、セミコロンの挿入と削除を自動化できるようになった。
この設定は「Visual Studio Code Insider」で利用でき、「Visual Studio 16.4 Preview 2」でも、「ツールオプション」メニューで利用できる。
「insert」(挿入)または「remove」(削除)の値を選ぶと、TypeScriptサービスで提供される自動インポートや抽出した型、他の生成コードのフォーマットにも影響する。設定をデフォルト値「ignore」(無視)のままにすると、現在のファイルで検出されたセミコロンの傾向に合わせて生成コードを整形する。
TypeScriptのWebサイト最上部のタブからアクセスできる公式の「Playground」(試用サイト)では、迅速なエラー修正やダーク/ハイコントラストモード、他のパッケージをインポートする際の自動的な型取得といった新機能が利用できるようになった。
さらに、「What's new」メニューから、インタラクティブなコードスニペットを使ったTypeScript 3.7の新機能の解説を閲覧できる。
加えて、TypeScriptのWebサイトの右上隅に検索フィールドを用意し、ハンドブックやリリースノートなどを対象にキーワード検索ができるようになった。この検索機能は、検索APIサービス「Algolia」を使って提供されている。
TypeScript 3.7では、ECMAScriptで最も要望の高い機能の一つであるオプショナルチェイニングを実装した。
オプショナルチェイニングの基本的な働きは、実行時にnullやundefinedが発生した場合、式の実行を直ちに停止できるようなコードを作成可能にすることだ。このためにオプションプロパティアクセスに向けて新しい「?.」演算子を追加した。
let x = foo?.bar.baz();
例えば、このコードスニペットは、次のような記述と同じことになる。
let x = (foo === null || foo === undefined) ? undefined : foo.bar.baz();
nullish coalescing演算子は、オプショナルチェイニングと密接に関係するECMAScriptの機能だ。演算子として「??」を用いる。
この機能は、nullやundefinedを処理する際に、デフォルト値に“フォールバックする”手法の一つだ。
let x = foo ?? bar();
例えば、このコードスニペットと同じ処理を実現するために、これまでは次のように記述していた。
let x = (foo !== null && foo !== undefined) ? foo : bar();
予期せぬ状態が発生すると、エラーをスロー(throw)する関数がある。こうした関数は“アサーション”関数と呼ばれる。
TypeScript 3.7では、アサーション関数をモデル化する“アサーションシグネチャ”という新しい考え方を導入した。
アサーションシグネチャの導入作業の一環として、どこでどの関数が呼び出されるかをより詳細にエンコードする必要が生じた。このことが、neverを返す関数のサポートを拡大するきっかけになったという。
関数がneverを返すのは、例外をスローしたか、停止エラー条件が発生したか、プログラムが終了したかのいずれかに該当する。
TypeScriptではこれまで、関数がundefinedを返した可能性がないこと、あるいは全てのコードパスから効果的に戻らなかったことを確認するには、次のように、関数の末尾にシンタックス上のシグナル(returnまたはthrow)が必要だった。このようにしてユーザーは、失敗した関数をreturnするようにしていた。
function dispatch(x: string | number): SomeType { if (typeof x === "string") { return doThingWithString(x); } else if (typeof x === "number") { return doThingWithNumber(x); } return process.exit(1); }
TypeScript 3.7では、こうしたneverを返す関数が呼び出されると、それらの関数が制御フローグラフに影響することを認識し、対処するようになった。
function dispatch(x: string | number): SomeType { if (typeof x === "string") { return doThingWithString(x); } else if (typeof x === "number") { return doThingWithNumber(x); } process.exit(1); }
TypeScriptでは、「--declaration」フラグを使って、「.ts」や「.tsx」ファイルのようなソースTypeScriptファイルから、「.d.ts」ファイル(宣言ファイル)を生成できる。.d.tsファイルを使用すると、オリジナルのソースコードを再チェック、ビルドすることなく、他のプロジェクトに対して型チェックを行うことができる。
残念ながら、--declarationには、これまで制限があった。TypeScriptとJavaScriptの入力ファイルを混合できる「--allowJs」のような設定とともに使えなかったのだ。
TypeScript 3.7では、この2つの機能を組み合わせて利用できるようになった。--allowJsを使う場合、TypeScriptはベストエフォートでJavaScriptソースコードを理解し、同等の表現で.d.tsファイルに保存する。例えば、次のようなコードを扱ったとしよう。
/** * @callback Job * @returns {void} */ /** Queues work */ export class Worker { constructor(maxDepth = 10) { this.started = false; this.depthLimit = maxDepth; /** * NOTE: queued jobs may add more items to queue * @type {Job[]} */ this.queue = []; } /** * Adds a work item to the queue * @param {Job} work */ push(work) { if (this.queue.length + 1 > this.depthLimit) throw new Error("Queue full!"); this.queue.push(work); } /** * Starts the queue if it has not yet started */ start() { if (this.started) return false; this.started = true; while (this.queue.length) { /** @type {Job} */(this.queue.shift())(); } return true; } }
このコードを次のような.d.tsファイルに変換する。
/** * @callback Job * @returns {void} */ /** Queues work */ export class Worker { constructor(maxDepth?: number); started: boolean; depthLimit: number; /** * NOTE: queued jobs may add more items to queue * @type {Job[]} */ queue: Job[]; /** * Adds a work item to the queue * @param {Job} work */ push(work: Job): void; /** * Starts the queue if it has not yet started */ start(): boolean; } export type Job = () => void;
型エイリアスには常に、再帰的な参照を使った場合に制限があった。型エイリアスは、どのように使用する場合でも、自身が表す型を必ず代替できなければならないからだ。だが場合によっては実現不可能である。そのためコンパイラは、次のような特定の再帰的なエイリアスを排除していた。
type Foo = Foo;
TypeScript 3.7では、型エイリアスの“トップレベル”で型引数の解決が先送りされた。例えば、JSONを表現する次のようなコードを例に挙げよう。
type Json = | string | number | boolean | null | JsonObject | JsonArray; interface JsonObject { [property: string]: Json; } interface JsonArray extends Array<Json> {}
TypeScript 3.7ではヘルパーインタフェースを使わずに、次のように書き換えられるようになった。
type Json = | string | number | boolean | null | { [property: string]: Json } | Json[];
また、今回の制限緩和により、タプルで型エイリアスを再帰的に参照することも可能になった。これまではエラーだった次のコードが、有効なTypeScriptコードになる。
type VirtualNode = | string | [string, { [key: string]: any }, ...VirtualNode[]]; const myNode: VirtualNode = ["div", { id: "parent" }, ["div", { id: "first-child" }, "I'm the first child"], ["div", { id: "second-child" }, "I'm the second child"] ];
Copyright © ITmedia, Inc. All Rights Reserved.