Upgrade to Pro — share decks privately, control downloads, hide ads and more …

型チェック 速度改善 奮闘記⌛

Kenta TSUNEMI
November 16, 2024

型チェック 速度改善 奮闘記⌛

Kenta TSUNEMI

November 16, 2024
Tweet

More Decks by Kenta TSUNEMI

Other Decks in Technology

Transcript

  1. 改善の要因は⼤きく分けると 3 つ👀 (パーセンテージは改善内容における割合) 1. Redux Toolkit 関連の型推論 (80%!!) 2.

    Extract による Instantiation (10%) 3. 不要なスキーマ定義‧チェック (10%) 改善の要因
  2. initialState の型に名前を付けて切り 出すことでキャッシュが効くように なり速度が改善。 1 ファイルにつき 800 - 900ms か

    かっていたのが 数 ms 程度で済むよ うに🚀 Typescript の Performance に関す る公式 doc にある Naming Complex Types のパターン Redux Toolkit (After)
  3. Redux Toolkit (Before / After) ある App の型チェックをトレースしたときの Before /

    After ⻘線で囲んだ部分が Redux Toolkit の createSlice をしているファイル
  4. export function getNode<T extends Node['type']>( condition: Condition, nodeId: NodeId, type?:

    T ): Extract<Node, { type: T }> export function getNode( condition: Condition, nodeId: NodeId, type: Node['type'] ) { // do something } 引数で受け取った type (リテラル 型の union) をもとに Extract した 型を返却する関数。 Extract<Node, { type: T }> の部分 でチェックに時間を要していた。 Extract (Before)
  5. export function getNode(condition: Condition, nodeId: NodeId): Node export function getNode(

    condition: Condition, nodeId: NodeId, type: 'condition' ): ConditionNode export function getNode( condition: Condition, nodeId: NodeId, type: 'operator' ): OperatorNode export function getNode( condition: Condition, nodeId: NodeId, type?: Node['type'] ) { // do something } 関数オーバーロードを利⽤すること で戻り値の情報は維持しつつ Extract を排除して、速度も改善🚀 コードが増え汎⽤性も失われたが、 このドメイン領域では type は 2 種 類しか存在せず、今後増えることも 考えにくかったため、 トレードオフを受け⼊れた形。 Extract (After)
  6. ある型(右図では最終⾏の Types) を定義するときに、不要な zod schema (最後から 2 ⾏⽬)を介して いた🥲 不要なスキーマ定義

    export const typeASchema = z.object({ type: z.literal('A'), name: z.string(), }); export type TypeA = z.infer<typeof typeASchema>; export const typeBSchema = z.object({ type: z.literal('B'), count: z.number(), }); export type TypeB = z.infer<typeof typeBSchema>; export const typeCSchema = z.object({ type: z.literal('C'), value: z.string(), }); export type TypeC = z.infer<typeof typeCSchema>; // ↓この typesSchema はただの中間介在物でしかない、、 const typesSchema = z.union([typeASchema, typeBSchema, typeCSchema]); export type Types = z.infer<typeof typesSchema>;
  7. --noEmit ビルド結果の js ファイルを出⼒しない --extendedDiagnotics tsc コマンドの対象ファイル数や各プロセスにかかった時間等が表⽰される 修正の結果、速度や Instantiations の数が変化したか確認するのに便利

    --generateTrace 指定したディレクトリに trace.json と types.json を出⼒する 速度改善には⽋かせない超重要オプション💡 tsc コマンドでのデータ取得 npx tsc -p path/to/tsconfig.json --noEmit --extendedDiagnostics --generateTrace traceDir
  8. VSCode のオプションを使う場合、 右図のように設定する。 ログの位置が⾮常にわかりにくいが、 コマンドパレットで tsserver.log を開いて、 そこからエクスプローラを開くことで ログのありかに辿り着ける。 VSCode

    を開き続けている間はログが取得され続 け、任意の期間だけログを取る事ができない😇 VSCode でのデータ取得(オプション) { "typescript.tsserver.enableTracing": true, "typescript.tsserver.log": "verbose" }
  9. VSCode の拡張機能を使うことでも データ取得が可能。オススメ! 前回の TSKaigi で登壇されていた ypresto さん作成の拡張機能! コマンドパレットから任意のタイミン グで

    trace ログの ON/OFF を切り替え られる👏 これのおかげで調査がめちゃ捗りまし た、ありがたやありがたや🙏 VSCode でのデータ取得(拡張機能)
  10. trace.json の解析にはツールを利⽤する about://tracing ブラウザに標準搭載されている。開くと Perfetto UI をオススメしてくる。 Perfetto UI Web

    アプリ。もともと Android ⽤のツールだった模様。 Speedscope ⭐ オススメ!軽くて操作も直感的で⼀番使いやすかった。 trace.json の解析
  11. 調査対象によっては types.json は不要 な場合もある。 最初は trace.json の出⼒が終わったタ イミングでいちいちプロセスを kill し

    たりしていたが、 tsc のコードに⼿を加えてしまうのが⼀ 番⼿っ取り早かった🔧 node_modules/typescript/lib/tsc.js の dumpTypes() をコメントアウト🥷 types.json が不要な場合は… [email protected] の例