Yet Another Perl Conference 2022
TypeScript へ型安全性を高めながらリプレースする@_kimuson 1きむそん @_kimuson
View Slide
自己紹介きむそん (kimsuon)Twitter: @_kimusonGithub: d-kimusonWeb エンジニア1年生ブログ: kimuson.dev@_kimuson 2
所属株式会社モバイルファクトリー駅奪取チーム@_kimuson 3
今日の話題TypeScript@_kimuson 4
TypeScriptJavaScript の拡張言語漸進的型付けによる型チェックトランスパイル静的型によってスケールしやすい@_kimuson 5
今日話すことTypeScript 移行のつらさTypeScript 移行のプラクティスがんばらない TypeScriptメリハリのある TypeScript弊社でのリプレース効果@_kimuson 6
オプション緩くするより、対象を絞れ!@_kimuson 7
移行するアプリケーション駅奪取: 先日10周年を迎えた位置ゲームアプリバックエンド: Perlフロントエンド: JavaScript + Vue.jsクライアント: WebView@_kimuson 8
TypeScript 移行の壁トランスパイルによる問題はほとんどない問題は型チェック大量の型エラーと向きあうことに@_kimuson 9
型アノテーションが存在しない@_kimuson 102 +function getUser(id: string): User {1 -function getUser(id) {3 // ...4 }
null チェックされてない@_kimuson 116 +elm.style.color = 'red'; // 型エラーなし1 const elm = document.getElementById('example'); // 値: null, 型: HTMLElement2 +if (elm === null) {3 + throw new Error('elm が null で想定してないよ :cry:');4 +}5 -elm.style.color = 'red'; // Object is possibly 'null'.
これらの型エラーを潰さないと移行できない@_kimuson 12
全部直す?@_kimuson 13
安全に直せるのか?型アノテーションランタイムに影響がないので、安全それ以外本番での挙動が変わることになる問題の切り分けが難しくなる@_kimuson 14
工数も厳しい全ての関数の引数に型アノテーションを追加全ての型エラーをきれいに修正移行を進めている間にも新しい実装が追加されていく@_kimuson 15
じゃあどうするの?@_kimuson 16
がんばらない TypeScript@_kimuson 17
がんばらない TypeScript「型チェックを緩くする」オプションが柔軟に提供「既存コードに合わせてオプションがんがんゆるくしちゃおうぜ」って方針まずは導入できることが大事@_kimuson 18
こんな感じでオプションを柔軟に 制御できる1. 公式の TSConfig リファレンス ↩︎@_kimuson 19[1]1 // tsconfig.json2 {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": false16 }17 }
設定が多くてわけわからない@_kimuson 20
strict だけ外せば大部分のエラーは消えるnoImplictAny: 必要な型アノテーションが抜けててもOKstrictNullCheckes: null なしでOK@_kimuson 21strict: 厳格にするオプションをまとめたもの1 function getUser(id) {} // id が any に解決されることで許容される1 const elm = document.getElementById('example'); // HTMLElement2 elm.style.color = 'red'; // strictNullCheckes で許容される
がんばらない TypeScript もつらいよすべてのファイルで型が信用できなくなってしまう後からの型安全性を高めることが難しい@_kimuson 22
型が信用できない…?@_kimuson 23
型と値がずれるnumber22 には '202' 文字列が入るが、型は number@_kimuson 241 function plus2(value /* :any */): number {2 return value + 23 }45 const number22: number = plus2('20') // '202'` ` ` `
型と値がずれるstrictNullChecks: false だと undefined が消えたりする@_kimuson 251 const elm = document.getElementById('not-existed-id'); // 値: null, 型: HTMLElement2 elm.style.color = 'red'; // Uncaught TypeError: Cannot read properties of null (reading 'style')
すべてのファイルで型が信用できない型チェックオプションが緩い → 型と値の不一致新規のコードを含めて TS のメリットが減ってしまうオプションが緩いので、静的に検知できる問題が減るメンテナブルなコードが残りにくい@_kimuson 26
がんばらない TypeScript もつらいよすべてのファイルで型が信用できなくなってしまう後からの型安全性を高めることが難しい@_kimuson 27
後からの型安全性を高めることが難しい新規で書くコードも型安全性を保証できない型安全性を高める = 型チェックオプションを硬くすること( strict: true )移行時に避けた大量のエラーを直す作業が必要@_kimuson 28` `
じゃあどうするのか@_kimuson 29
メリハリのある TypeScript@_kimuson 30
メリハリのある TypeScript「型チェックの範囲を狭める」アプローチコメントで行・ファイル単位で型エラーを無視できる移行時は型チェックオプションは硬いままエラーになるところは型エラーを無視@_kimuson 31
ts-expect-error: 行単位の型エラー無視@_kimuson 32次の行の型エラーは無視される1 const elm /* :HTMLElement | null */ = document.getElementById('not-existed-id');23 elm.style.color = 'red'; // Object is possibly 'null'.
ts-nocheck: ファイル単位の型エラー無視@_kimuson 33コメントがあるファイルの型エラーは無視される12 const elm /* :HTMLElement | null */ = document.getElementById('not-existed-id');3 elm.style.color = 'red'; // Object is possibly 'null'.45 parseInt(elm)
なにが嬉しいのか@_kimuson 34
型安全性にメリハリがつく目印型の信用度静的解析 心持ち@ts-nocheck低 無 補完が効きやすいだけの JavaScript@ts-expect-error中 有(型の信用度が低いので一部ではあるが検知できる)型は間違ってる可能性もあるから疑いつつ使う(静的に検知できる問題も多い)上記が存在しない高 有 型を全面的に信用することで恩恵を最大限受けられる@_kimuson 35
運用とともに型安全性が向上させやすい新規で書くコードは型安全性なコードに型安全性が徐々に向上させやすいts-nocheck, ts-expext-error を外すだけ@_kimuson 36
実際に弊社でリプレースを行った結果新規でのコーディングでは TS の恩恵が大きい一から構築した TypeScript とさほど遜色ないTS の恩恵を大きく受けながら開発できた型安全性は順調に向上中@_kimuson 37
型安全性は順調に向上中@_kimuson 38
がんばらない vs メリハリのある「がんばらないTypeScript」は移行コストを下げるまずは移行したほうが良い移行後に 型で 困ることが少ない「メリハリのあるTypeScript」は運用に適す移行の難易度・工数はあがるTypeScript の恩恵を受けやすい@_kimuson 39
まとめTypeScript にすると安全性・開発体験あがっていいよプロジェクトに合わせて「がんばらないTypeScript」か「メリハリのあるTypeScript」で@_kimuson 40
ご清聴ありがとうございました@_kimuson 41