https://github.com/microsoft/TypeScript/wiki/Performance
このページは、TypeScript のコンパイル速度や VS Code の型チェック速度が遅い場合の改善方法をまとめた公式ドキュメントです。
Microsoft が最初に強調しているのは、
「まずはコードや設定を改善するだけで大きく高速化できる」
という点です。
また現在は TypeScript 本体を Go に移植した TypeScript 7.0(TypeScript Go) の開発も進んでおり、ケースによっては最大 10 倍程度高速になると説明されています。
Microsoft が明確に推奨しています。
type User = BaseUser &
AuditInfo & {
name: string;
};
interface User extends BaseUser, AuditInfo {
name: string;
}
理由:
never が発生しやすいMicrosoft は
interface の型関係はキャッシュされるが、intersection 型全体はそうではない
と説明しています。
この Wiki が言っているのは、
「interface が常に速い」ではありません。
正確には
「オブジェクト型を合成するときは intersection より extends の方がコンパイラに優しい」
という話です。
つまり、
type User = {
id: string;
name: string;
};
と
interface User {
id: string;
name: string;
}
の比較ではなく、
type User = A & B & C;
と
interface User extends A, B, C {}
の比較です。([GitHub][1])
そのため、
「Type は遅い」
という解釈は正確ではありません。
function fetchUser() {
return {
id: "1",
name: "John",
};
}
↓
function fetchUser(): User {
return {
id: "1",
name: "John",
};
}
メリット
.d.ts 生成が軽くなる特に大規模プロジェクトでは効果が出やすいとされています。
type Element =
| DivElement
| SpanElement
| ImgElement
| ...
| VideoElement;
Union の各要素同士を比較する必要があり、
という問題があります。
interface HtmlElement {
id: string;
}
interface DivElement extends HtmlElement {}
interface ImgElement extends HtmlElement {}
共通の基底型を作る方が効率的です。
interface Service<T> {
execute<U>(
value: U
): U extends A
? ResultA
: U extends B
? ResultB
: ResultC;
}
毎回 Conditional Type を評価する必要があります。
type ExecuteResult<U> =
U extends A
? ResultA
: U extends B
? ResultB
: ResultC;
interface Service<T> {
execute<U>(value: U): ExecuteResult<U>;
}
名前付き型にするとコンパイラがキャッシュしやすくなります。
大規模プロジェクトでは
client
server
shared
のように分割することが推奨されています。
メリット
Microsoft の経験則では、
5〜20 プロジェクト程度
がバランスが良いとのことです。
実際にはこれが原因で遅くなっているケースが非常に多いです。
{
"include": ["**/*"]
}
これで
node_modules
dist
coverage
まで読み込んでしまう。
{
"compilerOptions": {
"types": []
}
}
必要なものだけ追加。
{
"compilerOptions": {
"types": ["node", "mocha"]
}
}
これにより型解決コストを削減できます。
{
"compilerOptions": {
"incremental": true
}
}
.tsbuildinfo を利用して差分ビルドを行います。
コンパイルが遅いときはまずこれ。
rm -f tsconfig.tsbuildinfo && tsc --extendedDiagnostics
# またはこちらでもok
tsc --extendedDiagnostics --incremental false
例:
Files: 1200
Types: 85000
Check time: 12.5s
確認できる項目:
| 項目 | 内容 |
|---|---|
| Parse time | パース時間 |
| Bind time | シンボル構築 |
| Check time | 型チェック |
| Emit time | 出力 |
| Memory used | メモリ使用量 |
どこが遅いか特定できます。
TypeScript の公式ガイドを踏まえると、
type User = {
id: string;
name: string;
};
でも
interface User {
id: string;
name: string;
}
でもほぼ問題ない。
複数型の合成では
type User = A & B & C;
より
interface User extends A, B, C {}
を推奨。