TypeScript 5.0 の新機能: 宣言子、Const 型、列挙型の改善、速度、その他多数!
公開: 2023-04-15TypeScript 5.0 は 2023 年 3 月 16 日に正式にリリースされ、誰でも使用できるようになりました。 このリリースでは、TypeScript をより小さく、よりシンプルに、より高速にすることを目的として、多くの新機能が導入されています。
この新しいリリースでは、クラスのカスタマイズ用にデコレーターが最新化され、クラスとそのメンバーを再利用可能な方法でカスタマイズできます。 開発者は、型パラメータ宣言に const 修飾子を追加できるようになり、const のような推論をデフォルトにすることができます。 また、新しいリリースでは、すべての列挙型がユニオン列挙型になり、コード構造が簡素化され、TypeScript エクスペリエンスが高速化されます。
この記事では、TypeScript 5.0 で導入された変更点を探り、その新しい機能と能力を詳しく見ていきます。
TypeScript 5.0 入門
TypeScript は、npm を使用してプロジェクトにインストールできる公式のコンパイラです。 プロジェクトで TypeScript 5.0 の使用を開始する場合は、プロジェクトのディレクトリで次のコマンドを実行できます。
npm install -D typescript
これにより、コンパイラがnode_modulesディレクトリにインストールされ、 npx tsc
コマンドで実行できるようになります。
このドキュメントでは、Visual Studio Code で新しいバージョンの TypeScript を使用する方法についても説明しています。
このTypeScript 5.0 の新機能
この記事では、TypeScript に導入された 5 つの主要な更新について説明します。 これらの機能は次のとおりです。
近代化されたデコレータ
デコレータはしばらくの間、実験的なフラグの下で TypeScript に存在していましたが、新しいリリースでは ECMAScript の提案に対応するようになりました。これは現在ステージ 3 にあり、TypeScript に追加される段階にあることを意味します。
デコレーターは、クラスとそのメンバーの動作を再利用可能な方法でカスタマイズする方法です。 たとえば、 greet
とgetAge
の 2 つのメソッドを持つクラスがあるとします。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}.`); } getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
実際の使用例では、このクラスには、いくつかの非同期ロジックを処理するより複雑なメソッドが必要であり、メソッドのデバッグを支援するためにいくつかのconsole.log
呼び出しをスローしたい場合などに、副作用があります。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log('LOG: Method Execution Starts.'); console.log(`Hello, my name is ${this.name}.`); console.log('LOG: Method Execution Ends.'); } getAge() { console.log('LOG: Method Execution Starts.'); console.log(`I am ${this.age} years old.`); console.log('Method Execution Ends.'); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
これは頻繁に発生するパターンであり、すべてのメソッドに適用できるソリューションがあると便利です。
ここでデコレータの出番です。 次のように表示されるdebugMethod
という名前の関数を定義できます。
function debugMethod(originalMethod: any, context: any) { function replacementMethod(this: any, ...args: any[]) { console.log('Method Execution Starts.'); const result = originalMethod.call(this, ...args); console.log('Method Execution Ends.'); return result; } return replacementMethod; }
上記のコードでは、 debugMethod
元のメソッド ( originalMethod
) を受け取り、次のことを行う関数を返します。
- 「メソッドの実行が開始されました。」というメッセージをログに記録します。
- 元のメソッドとそのすべての引数 (これを含む) を渡します。
- 「メソッドの実行が終了しました。」というメッセージをログに記録します。
- 元のメソッドが返したものを返します。
以下のコードに示すように、デコレーターを使用することで、 debugMethod
をメソッドに適用できます。
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } @debugMethod greet() { console.log(`Hello, my name is ${this.name}.`); } @debugMethod getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();
これにより、次のように出力されます。
LOG: Entering method. Hello, my name is Ron. LOG: Exiting method. LOG: Entering method. I am 30 years old. LOG: Exiting method.
デコレーター関数 ( debugMethod
) を定義するとき、 context
2 番目のパラメーターが渡されます (これは context オブジェクトであり、装飾されたメソッドがどのように宣言されたか、およびメソッドの名前に関する有用な情報が含まれています)。 debugMethod
を更新して、 context
オブジェクトからメソッド名を取得できます。
function debugMethod( originalMethod: any, context: ClassMethodDecoratorContext ) { const methodName = String(context.name); function replacementMethod(this: any, ...args: any[]) { console.log(`'${methodName}' Execution Starts.`); const result = originalMethod.call(this, ...args); console.log(`'${methodName}' Execution Ends.`); return result; } return replacementMethod; }
コードを実行すると、 debugMethod
デコレーターで装飾された各メソッドの名前が出力に含まれるようになります。
'greet' Execution Starts. Hello, my name is Ron. 'greet' Execution Ends. 'getAge' Execution Starts. I am 30 years old. 'getAge' Execution Ends.
デコレータでできることは他にもあります。 TypeScript でデコレータを使用する方法の詳細については、元のプル リクエストを自由に確認してください。
const 型パラメータの導入
これは、関数を呼び出すときに得られる推論を改善するために、ジェネリックを使用した新しいツールを提供するもう 1 つの大きなリリースです。 デフォルトでは、 const
で値を宣言すると、TypeScript はリテラル値ではなく型を推測します。
// Inferred type: string[] const names = ['John', 'Jake', 'Jack'];
これまで、目的の推論を実現するには、「as const」を追加して const アサーションを使用する必要がありました。
// Inferred type: readonly ["John", "Jake", "Jack"] const names = ['John', 'Jake', 'Jack'] as const;
関数を呼び出すときも同様です。 以下のコードでは、推測される国の型はstring[]
です。
type HasCountries = { countries: readonly string[] }; function getCountriesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: string[] const countries = getCountriesExactly({ countries: ['USA', 'Canada', 'India'] });
as const
アサーションを追加することが以前に修正する 1 つの方法であった、より具体的なタイプが必要になる場合があります。
// Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] } as const);
これを覚えて実装するのは難しい場合があります。 ただし、TypeScript 5.0 では、const 修飾子を型パラメーター宣言に追加できる新しい機能が導入されています。これにより、const のような推論がデフォルトで自動的に適用されます。
type HasCountries = { countries: readonly string[] }; function getNamesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] });
const
型のパラメーターを使用すると、開発者はコード内で意図をより明確に表現できます。 変数が定数であり、変更されないことが意図されている場合、 const
型パラメーターを使用すると、誤って変更されることがなくなります。
TypeScript で const 型パラメーターがどのように機能するかの詳細については、元のプル リクエストを確認できます。
列挙型の改善
TypeScript の列挙型は、開発者が一連の名前付き定数を定義できるようにする強力な構造です。 TypeScript 5.0 では、列挙型がさらに柔軟で便利になるように改良が加えられました。
たとえば、次の列挙型が関数に渡された場合:
enum Color { Red, Green, Blue, } function getColorName(colorLevel: Color) { return colorLevel; } console.log(getColorName(1));
TypeScript 5.0 が導入される前は、間違ったレベル番号を渡すことができ、エラーはスローされませんでした。 しかし、TypeScript 5.0 の導入により、すぐにエラーがスローされます。
また、新しいリリースでは、計算されたメンバーごとに一意の型を作成することにより、すべての列挙型を共用体列挙型にします。 この機能強化により、すべての列挙型を絞り込み、そのメンバーを型として参照できるようになります。
enum Color { Red, Purple, Orange, Green, Blue, Black, White, } type PrimaryColor = Color.Red | Color.Green | Color.Blue; function isPrimaryColor(c: Color): c is PrimaryColor { return c === Color.Red || c === Color.Green || c === Color.Blue; } console.log(isPrimaryColor(Color.White)); // Outputs: false console.log(isPrimaryColor(Color.Red)); // Outputs: true
TypeScript 5.0 のパフォーマンスの向上
TypeScript 5.0 には、コード構造、データ構造、およびアルゴリズム拡張における多数の重要な変更が含まれています。 これにより、インストールから実行まで TypeScript のエクスペリエンス全体が改善され、より高速で効率的なものになりました。
たとえば、TypeScript 5.0 と 4.9 のパッケージ サイズの違いは非常に印象的です。
TypeScript は最近、名前空間からモジュールに移行され、スコープ ホイストなどの最適化を実行できる最新のビルド ツールを活用できるようになりました。 また、非推奨のコードをいくつか削除したことで、TypeScript 4.9 の 63.8 MB のパッケージ サイズから約 26.4 MB 削減されました。
TypeScript 5.0 と 4.9 の間で、速度とサイズの点でさらに興味深い利点がいくつかあります。
シナリオ | TS 4.9 に関連する時間またはサイズ |
material-ui ビルド時間 | 90% |
TypeScript コンパイラの起動時間 | 89% |
劇作家のビルド時間 | 88% |
TypeScript コンパイラのセルフビルド時間 | 87% |
Outlook Web ビルド時間 | 82% |
VS コードのビルド時間 | 80% |
typescript npm パッケージサイズ | 59% |
より良いモジュール解像度のためのバンドル解像度
TypeScript でインポート ステートメントを記述する場合、コンパイラはインポートが何を参照しているかを知る必要があります。 モジュール解決を使用してこれを行います。 たとえば、 import { a } from "moduleA"
を記述する場合、コンパイラはmoduleA
内のa
の定義を認識して、その使用をチェックする必要があります。
TypeScript 4.7 では、 --module
およびmoduleResolution
設定にnode16
およびnodenext
の 2 つの新しいオプションが追加されました。
これらのオプションの目的は、Node.js の ECMAScript モジュールの正確なルックアップ ルールをより正確に表すことでした。 ただし、このモードには、他のツールでは適用されないいくつかの制限があります。
たとえば、Node.js の ECMAScript モジュールでは、相対インポートが正しく機能するためにファイル拡張子を含める必要があります。
import * as utils from "./utils"; // Wrong import * as utils from "./utils.mjs"; // Correct
TypeScript は、「moduleResolution バンドラー」と呼ばれる新しい戦略を導入しました。 この戦略は、TypeScript 構成ファイルの「compilerOptions」セクションに次のコードを追加することで実装できます。
{ "compilerOptions": { "target": "esnext", "moduleResolution": "bundler" } }
この新しい戦略は、ハイブリッド ルックアップ戦略を利用する Vite、esbuild、swc、Webpack、Parcel などの最新のバンドラーを使用する場合に適しています。
moduleResolution
バンドラーが TypeScript でどのように機能するかについて詳しくは、元のプル リクエストとその実装を確認してください。
非推奨
TypeScript 5.0 には、ランタイム要件、lib.d.ts の変更、API の重大な変更など、いくつかの減価償却が伴います。
- ランタイム要件: TypeScript は ECMAScript 2018 をターゲットにするようになり、パッケージはエンジンの最小期待値を 12.20 に設定します。 したがって、Node.js のユーザーが TypeScript 5.0 を使用するには、バージョン 12.20 以降が必要です。
- lib.d.ts の変更: DOM の型の生成方法にいくつかの変更があり、既存のコードに影響を与える可能性があります。 特に、特定のプロパティが数値から数値リテラル型に変換され、切り取り、コピー、および貼り付けのイベント処理のプロパティとメソッドがインターフェイス間で移動されました。
- API の重大な変更:いくつかの不要なインターフェイスが削除され、いくつかの正確性が改善されました。 TypeScript 5.0 もモジュールに移行しました。
TypeScript 5.0 では、 target: ES3
、 out
、 noImplicitUseStrict
、 keyofStringsOnly
、 suppressExcessPropertyErrors
、 suppressImplicitAnyIndexErrors
、 noStrictGenericChecks
、 charset
、 importsNotUsedAsValues
、 preserveValueImports
、およびプロジェクト参照の先頭に追加します。
これらの構成は TypeScript 5.5 まで有効ですが、まだ使用しているユーザーに警告が発行されます。
まとめ
この記事では、列挙型、バンドラーの解決、const 型パラメーターの改善、速度とサイズの改善など、TypeScript 5.0 がもたらす主要な機能と改善点のいくつかを学びました。
次のプロジェクトで TypeScript を検討している場合は、Kinsta のアプリケーション ホスティングを無料でお試しください。
今ではあなたの番です! TypeScript 5.0 で最も魅力的な機能や改善点は何ですか? 私たちが見落としているかもしれない重要なものはありますか? コメントでお知らせください。