🎉

TypeScript 5.0 Beta の新機能を雑にまとめる

2023/01/31に公開

先日 TypeScript 5.0 Beta がリリースされた ので、そこで追加された新機能の話をします。
全体的に雑にまとめてあるので、詳しい情報は公式ブログを参照してください。

Decorators

TC39 で Stage3 に達したデコレータ(Stage 3 Decorators と呼ぶことにする)が使えるようになりました。
https://github.com/tc39/proposal-decorators

元々 TypeScript では、 experimentalDecorators フラグを付けることでデコレータを使うことができました。
(Legacy Decorators と呼ぶことにします)

しかしLegacy Decoratorsは古いプロポーザルを元にしたもので、Stage 3 Decorators とは互換性がありません。
例えば、Stage 3 Decorator では、クラスにデコレータを付ける場合、 export キーワードがある場合は export キーワードの後にデコレータを書く必要があります。
また、引数にデコレータを付けることはできません。

// Legacy Decorators
@register
export class Foo {
  constructor(@inject(Bar) bar: Bar) {}
}

// Stage 3 Decorators
// exportキーワードがある場合、デコレータはその後に書く必要がある
export
@register
class Foo {
  // 引数にデコレータをつけることができない
  // constructor(@inject(Bar) bar: Bar) {}
}

ただ、今後の提案で、標準にこのような仕様が追加される可能性はあるかもしれません。

const Type Parameters

型パラメータに const 修飾子をつけることができるようになりました。
呼び出し側で as const をつけなくても、呼び出される側で同様の型推論ができるようになりました。

type HasNames = { readonly names: string[] };
function getNamesExactly<T extends HasNames>(arg: T): T["names"] {
  return arg.names;
}

// Inferred type: string[]
const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });


type HasNames = { names: readonly string[] };
function getNamesExactlyWithConst<const T extends HasNames>(arg: T): T["names"] {
    return arg.names;
}

// Inferred type: readonly ["Alice", "Bob", "Eve"]
// Note: Didn't need to write 'as const' here
const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });

Supporting Multiple Configuration Files in extends

compilerOptions.extends に複数の設定ファイルを指定できるようになりました。

{
  "compilerOptions": {
    "extends": ["a", "b", "c"]
  }
}

All enums Are Union enums

enum の値に定数以外の値を指定できるようになりました。

enum E {
  Foo = Math.random(),
}

--moduleResolution bundler

moduleResolutionbundler を指定できるようになりました。

いままでは、主に nodenode16nodenextを指定できました。

node15nodenext では、相対パスでインポートする場合、拡張子を付ける必要がありました。
一方、node は拡張子を付けなくても動きますが、conditional exports でインポートを解決するときに require を使い、exports フィールドを使いません。

webpack などのバンドラは、これらの中間のような振る舞いをします。
拡張子を付ける必要がなく、conditional exports では import を優先します。
bundler は名前の通り、バンドラのように振る舞います。

conditional exports を使うかどうか、使う場合どのフィールドを優先的に使うか、といった挙動は設定で変更可能です。

--verbatimModuleSyntax

verbatimModuleSyntax フラグが追加されました。
このフラグを指定すると、type 修飾子が付いている import/export 文は出力されなくなり、
付いていないものはそのまま出力されます。

いままでも、下記のようなモジュールの出力に関するフラグはありましたが、
複雑だったり、エッジケースで期待しない挙動をしたりすることがありました。

  • importsNotUsedAsValues
  • preserveValueImports
  • isolatedModules

verbatimModuleSyntax フラグはルールがシンプルでわかりやすいのが特徴です。

Support for export type *

type-only imports 周りの改善です。
export type * from "hoge"export type * as hoge from "hoge" のような構文を使えるようになりました。

JSDoc 関連の変更

TypeScript は JSDoc アノテーションを書けば JavaScript の型チェックもしてくれますが、
satisfies オペレータやオーバーロードが JSDoc で使えるようになりました。

  • @satisfies Support in JSDoc
  • @overload Support in JSDoc

Passing Emit-Specific Flags Under --build

--build フラグと一緒に下記フラグを指定できるようになりました。

  • --declaration
  • --emitDeclarationOnly
  • --declarationMap
  • --soureMap
  • --inlineSourceMap

Exhaustive switch/case Completions

switch 文でリテラル型を検査する場合、網羅的に case を書くように補完してくれるようになりましたs。

Speed, Memory, and Package Size Optimizations

内部的な最適化の話です。
ライブラリのビルド時間が早くなったり、コンパイル時のメモリ使用量が減ったり、TypeScript 自体のパッケージサイズが小さくなったりした、ということです。

Discussion