$30 off During Our Annual Pro Sale. View Details »

TypeScript へ型安全性を高めながらリプレースする

TypeScript へ型安全性を高めながらリプレースする

Yet Another Perl Conference 2022

きむそん

March 04, 2022
Tweet

Transcript

  1. TypeScript へ型安全性を高めな がらリプレースする @_kimuson 1 きむそん @_kimuson

  2. 自己紹介 きむそん (kimsuon) Twitter: @_kimuson Github: d-kimuson Web エンジニア1年生 ブログ:

    kimuson.dev @_kimuson 2
  3. 所属 株式会社モバイルファクトリー 駅奪取チーム @_kimuson 3

  4. 今日の話題 TypeScript @_kimuson 4

  5. TypeScript JavaScript の拡張言語 漸進的型付けによる型チェック トランスパイル 静的型によってスケールしやすい @_kimuson 5

  6. 今日話すこと TypeScript 移行のつらさ TypeScript 移行のプラクティス がんばらない TypeScript メリハリのある TypeScript 弊社でのリプレース効果

    @_kimuson 6
  7. オプション緩くするより、対象を絞れ! @_kimuson 7

  8. 移行するアプリケーション 駅奪取: 先日10周年を迎えた位置ゲームアプリ バックエンド: Perl フロントエンド: JavaScript + Vue.js クライアント:

    WebView @_kimuson 8
  9. TypeScript 移行の壁 トランスパイルによる問題はほとんどない 問題は型チェック 大量の型エラーと向きあうことに @_kimuson 9

  10. 型アノテーションが存在しない @_kimuson 10 2 +function getUser(id: string): User { 1

    -function getUser(id) { 3 // ... 4 }
  11. null チェックされてない @_kimuson 11 6 +elm.style.color = 'red'; // 型エラーなし

    1 const elm = document.getElementById('example'); // 値: null, 型: HTMLElement 2 +if (elm === null) { 3 + throw new Error('elm が null で想定してないよ :cry:'); 4 +} 5 -elm.style.color = 'red'; // Object is possibly 'null'.
  12. これらの型エラーを潰さないと移行できない @_kimuson 12

  13. 全部直す? @_kimuson 13

  14. 安全に直せるのか? 型アノテーション ランタイムに影響がないので、安全 それ以外 本番での挙動が変わることになる 問題の切り分けが難しくなる @_kimuson 14

  15. 工数も厳しい 全ての関数の引数に型アノテーションを追加 全ての型エラーをきれいに修正 移行を進めている間にも新しい実装が追加されていく @_kimuson 15

  16. じゃあどうするの? @_kimuson 16

  17. がんばらない TypeScript @_kimuson 17

  18. がんばらない TypeScript 「型チェックを緩くする」オプションが柔軟に提供 「既存コードに合わせてオプションがんがんゆるくしち ゃおうぜ」って方針 まずは導入できることが大事 @_kimuson 18

  19. こんな感じでオプションを柔軟に 制御できる 1. 公式の TSConfig リファレンス ↩︎ @_kimuson 19 [1]

    1 // tsconfig.json 2 { 3 "compilerOptions": { 4 "module": "commonjs", 5 "target": "es2020", 6 "outDir": "dist", 7 "strict": true, 8 "declaration": true, 9 "moduleResolution": "node", 10 "noEmit": false, 11 "skipLibCheck": true, 12 "noUncheckedIndexedAccess": true, 13 "noErrorTruncation": true, 14 "forceConsistentCasingInFileNames": true, 15 "allowJs": false 16 } 17 }
  20. 設定が多くてわけわからない @_kimuson 20

  21. strict だけ外せば大部分のエラーは消える noImplictAny: 必要な型アノテーションが抜けててもOK strictNullCheckes: null なしでOK @_kimuson 21 strict:

    厳格にするオプションをまとめたもの 1 function getUser(id) {} // id が any に解決されることで許容される 1 const elm = document.getElementById('example'); // HTMLElement 2 elm.style.color = 'red'; // strictNullCheckes で許容される
  22. がんばらない TypeScript もつらいよ すべてのファイルで型が信用できなくなってしまう 後からの型安全性を高めることが難しい @_kimuson 22

  23. 型が信用できない…? @_kimuson 23

  24. 型と値がずれる number22 には '202' 文字列が入るが、型は number @_kimuson 24 1 function

    plus2(value /* :any */): number { 2 return value + 2 3 } 4 5 const number22: number = plus2('20') // '202' ` ` ` `
  25. 型と値がずれる strictNullChecks: false だと undefined が消えたりする @_kimuson 25 1 const

    elm = document.getElementById('not-existed-id'); // 値: null, 型: HTMLElement 2 elm.style.color = 'red'; // Uncaught TypeError: Cannot read properties of null (reading 'style')
  26. すべてのファイルで型が信用できない 型チェックオプションが緩い → 型と値の不一致 新規のコードを含めて TS のメリットが減ってしまう オプションが緩いので、静的に検知できる問題が減る メンテナブルなコードが残りにくい @_kimuson

    26
  27. がんばらない TypeScript もつらいよ すべてのファイルで型が信用できなくなってしまう 後からの型安全性を高めることが難しい @_kimuson 27

  28. 後からの型安全性を高めることが難しい 新規で書くコードも型安全性を保証できない 型安全性を高める = 型チェックオプションを硬くするこ と( strict: true ) 移行時に避けた大量のエラーを直す作業が必要

    @_kimuson 28 ` `
  29. じゃあどうするのか @_kimuson 29

  30. メリハリのある TypeScript @_kimuson 30

  31. メリハリのある TypeScript 「型チェックの範囲を狭める」アプローチ コメントで行・ファイル単位で型エラーを無視できる 移行時は型チェックオプションは硬いまま エラーになるところは型エラーを無視 @_kimuson 31

  32. ts-expect-error: 行単位の型エラー無視 @_kimuson 32 次の行の型エラーは無視される 1 const elm /* :HTMLElement

    | null */ = document.getElementById('not-existed-id'); 2 3 elm.style.color = 'red'; // Object is possibly 'null'.
  33. ts-nocheck: ファイル単位の型エラー無視 @_kimuson 33 コメントがあるファイルの型エラーは無視される 1 2 const elm /*

    :HTMLElement | null */ = document.getElementById('not-existed-id'); 3 elm.style.color = 'red'; // Object is possibly 'null'. 4 5 parseInt(elm)
  34. なにが嬉しいのか @_kimuson 34

  35. 型安全性にメリハリがつく 目印 型の 信用 度 静的解析 心持ち @ts- nocheck 低

    無 補完が効きやすいだけの JavaScript @ts- expect- error 中 有(型の信用度が低いので一部で はあるが検知できる) 型は間違ってる可能性もあるから疑いつつ使う (静的に検知できる問題も多い) 上記が存在 しない 高 有 型を全面的に信用することで恩恵を最大限受けら れる @_kimuson 35
  36. 運用とともに型安全性が向上させやすい 新規で書くコードは型安全性なコードに 型安全性が徐々に向上させやすい ts-nocheck, ts-expext-error を外すだけ @_kimuson 36

  37. 実際に弊社でリプレースを行った結果 新規でのコーディングでは TS の恩恵が大きい 一から構築した TypeScript とさほど遜色ない TS の恩恵を大きく受けながら開発できた 型安全性は順調に向上中

    @_kimuson 37
  38. 型安全性は順調に向上中 @_kimuson 38

  39. がんばらない vs メリハリのある 「がんばらないTypeScript」は移行コストを下げる まずは移行したほうが良い 移行後に 型で 困ることが少ない 「メリハリのあるTypeScript」は運用に適す 移行の難易度・工数はあがる

    TypeScript の恩恵を受けやすい @_kimuson 39
  40. まとめ TypeScript にすると安全性・開発体験あがっていいよ プロジェクトに合わせて「がんばらないTypeScript」か 「メリハリのあるTypeScript」で @_kimuson 40

  41. ご清聴ありがとうございました @_kimuson 41