[[Microsoft]]の[[TypeScript]]プロジェクトWikiの1項目。パフォーマンスに関する重要事項がまとめられている。 ## Writing Easy-to-Compile Code > [!caution] > すべてのケースで厳守する必要はない。パフォーマンスとそれ以外のトレードオフを考慮して、ケースごとに適切な選択をすること。 ### Preferring Interfaces Over Intersections > [[交差型よりインターフェースの継承を使用する (TypeScript)|交差型よりインターフェースの継承を使用する]] ### 型アノテーションを使う 特に関数の返却型は推論コストがかかる。 #### No Good ```ts // 返却型を明示しなくても推論可能だが、これが積み重なると推論コストがかかってしまう function sum(x: number, y: number) { return x + y; } ``` #### Good ```ts function sum(x: number, y: number): number { return x + y; } ``` ### Preferring Base Types Over Unions [[ユニオン型 (TypeScript)|ユニオン型]]ではなく[[インターフェース (TypeScript)|インターフェース]]の[[extends (JavaScript)|extends]]でも要件を満たすならそちらの方が高速。ただし、**`drink: Drink` を具象クラスの `Coffee` や `Tea` に[[Narrowing]]できなくなる** ので、`Coffee` や `Tea` 特有の[[プロパティ (TypeScript)|プロパティ]]を意識する必要がある場合は利用できない。 また、選択肢が2~3程度の[[ユニオン型 (TypeScript)|ユニオン型]]ならパフォーマンスの差は誤差なので気にする必要はない。 #### No Good ```ts interface Coffee { brand: "Starbucks" | "Doutor" | "Tully's"; type: string; price: number; } interface Tea { brand: "Twinings" | "Lipton"; flavor: string; price: number; } type Drink = Coffee | Tea; declare function describeDrink(drink: Drink): string; ``` #### Good ```ts interface Drink { brand: "Starbucks" | "Doutor" | "Tully's" | "Twinings" | "Lipton"; price: number; } interface Coffee extends Drink { brand: "Starbucks" | "Doutor" | "Tully's"; type: string; } interface Tea extends Drink { brand: "Twinings" | "Lipton"; flavor: string; } declare function describeDrink(drink: Drink): string; ``` ### Naming Complex Types [[型エイリアス (TypeScript)|型エイリアス]]で複雑な型定義を一度行うことによって、型定義のキャッシュを有効活用しパフォーマンスを向上できる。可読性の意味でも中間定義はしておいて損はない。 #### No Good ```ts // Employee.id が呼びだされるたびに条件付き型が評価される interface Employee<C> { id: C extends "N-company" ? `N${string}` : C extends "S-company" ? `S${string}` : never; } ``` #### Good ```ts // Employee.id: CompanyId<C> が一度呼び出されれば次回以降はCが同じならキャッシュが利用される type CompanyId<C> = C extends "N-company" ? `N${string}` : C extends "S-company" ? `S${string}` : never; interface Employee<C> { id: CompanyId<C>; } ```