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

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

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

Yet Another Perl Conference 2022

きむそん

March 04, 2022
Tweet

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

  4. 今日の話題
    TypeScript
    @_kimuson 4

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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'.

    View Slide

  12. これらの型エラーを潰さないと移行できない
    @_kimuson 12

    View Slide

  13. 全部直す?
    @_kimuson 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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 }

    View Slide

  20. 設定が多くてわけわからない
    @_kimuson 20

    View Slide

  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 で許容される

    View Slide

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

    View Slide

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

    View Slide

  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'
    ` ` ` `

    View Slide

  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')

    View Slide

  26. すべてのファイルで型が信用できない
    型チェックオプションが緩い → 型と値の不一致
    新規のコードを含めて TS のメリットが減ってしまう
    オプションが緩いので、静的に検知できる問題が減る
    メンテナブルなコードが残りにくい
    @_kimuson 26

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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'.

    View Slide

  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)

    View Slide

  34. なにが嬉しいのか
    @_kimuson 34

    View Slide

  35. 型安全性にメリハリがつく
    目印
    型の
    信用

    静的解析 心持ち
    @ts-
    nocheck
    低 無 補完が効きやすいだけの JavaScript
    @ts-
    expect-
    error
    中 有(型の信用度が低いので一部で
    はあるが検知できる)
    型は間違ってる可能性もあるから疑いつつ使う
    (静的に検知できる問題も多い)
    上記が存在
    しない
    高 有 型を全面的に信用することで恩恵を最大限受けら
    れる
    @_kimuson 35

    View Slide

  36. 運用とともに型安全性が向上させやすい
    新規で書くコードは型安全性なコードに
    型安全性が徐々に向上させやすい
    ts-nocheck, ts-expext-error を外すだけ
    @_kimuson 36

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide