見出し画像

Vue3+TSプロジェクトにType Checkを段階的に取り入れる方法を考える

諸般の事情によりVueでTypescriptを使っているが型チェックを入れることができないみたいなことってあると思います.例えば既存の型エラーが1000個ぐらいあるとかw
それに,viteは型チェックしないよというスタンスなので,型チェックなくてもビルドできちゃうし…
ということで,今回はどうやってVue3+TSプロジェクトに型チェックを導入するか考えていきます

VueのSFCをビルド時に型チェックする

vueで型チェックする方法には vue-tsc を利用します

$ npm i vue-tsc -D
$ vue-tsc --noEmit

これで,.vueファイル(SFC)の<script>も<template>も型チェックできます.

(ただし,typescript5のcomposite を使うときは vue-tsc --buildにする必要があるよです.https://github.com/vuejs/create-vue/issues/267

一気に直すか,徐々に直すか?

こういった大きめなリファクタリングなりマイグレーションなりをするときは,一気に全部直すかそれとも一部ずつ徐々に直すかで分かれると思います.
一気に直す場合は気合で突き進むしかなく面白みがないので,今回は徐々に直していく前提で考えます.

徐々に直していく場合は,直している途中に機能開発等で他から新たな型エラーが入ってくる問題を解決する必要があります.型エラーを直しても直しても無くならないという賽の河原の石積み状態です.(型エラーを直すこと自体には意味ありますが)
では,このシーシュポスの岩状態を回避するにはどうすればいいのでしょうか?

新たな型エラーが増えないようにしつつ,既存のエラーを潰す方法

単純に型エラーを直したファイルから型チェックすればよいです.今回は3つの方法を紹介します.

方法1:`@ts-expect-error`

ひたすら既存のエラー箇所に@ts-expect-errorをつけます.

@ts-expect-errorはSFCの<script>部分もしくはtsファイルでのみ有効です.
<template>内では @vue-expect-error (https://github.com/vuejs/language-tools/releases/tag/v1.8.0) を利用します

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'

// @ts-expect-error
const openReadmeInEditor: number = () => fetch(`/__open-in-editor?file=README.md?${e}`)
</script>

<template>
  <header>
    <!-- @vue-expect-error -->
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" @click="openReadmeInEditor"/>

    <div class="wrapper">
      <HelloWorld msg="You did it!" />

      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>

@ts-ignoreではなく,@ts-expect-errorを使う理由は,もし@ts-expect-errorの下の行にエラーが無いときは,これ自体がエラーとして検知されるので,しっかり,エラーを解決 -> @ts-expect-errorを消す というオペレーションを保証できるからです.

error TS2578: Unused '@ts-expect-error' directive.
  1. 型エラーが発生している箇所全てに @ts-expect-error をつける

  2. 型エラーを直したファイルから@ts-expect-errorを外す

ステップ1が大変ですが,頑張ってスクリプトで自動化するなどの方法はありそうです.

方法2:`@ts-nocheck` 

これは型チェックを無視したいファイルの先頭に @ts-nocheckを付ける方法です

<script setup lang="ts">
// @ts-nocheck
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'

const openReadmeInEditor: number = () => fetch(`/__open-in-editor?file=README.md`)
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" @click="openReadmeInEditor"/>

    <div class="wrapper">
      <HelloWorld msg="You did it!" />

      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>
  1. 型エラーが発生しているファイル全てに @ts-nocheck をつける

  2. 型エラーを直したファイルから @ts-nocheck を外す

ステップ1が割とめんどくさいですが,頑張ればスクリプトで自動化もできそうです.

あと,エラー解決し終わったファイルの@ts-nocheckを消すのを忘れないようにしないとですね.

方法3:loose-ts-check 

最後は別ツールに乗っかるパターンです.あまり有名なツールでは無いので,いささか不安ですが,プロダクションで利用されるわけではないので,大丈夫ということにします

  1. npm install loose-ts-check --save-dev
    でインストール

  2. vue-tsc --noEmit | loose-ts-check --init
    で既存のエラーを無視するよう設定

  3. vue-tsc --noEmit | loose-ts-check
    で既存のエラーを無視しつつ,型チェック

vue-tsc --noEmit | loose-ts-check --auto-update
で,無視するエラーリストを更新もできるようです.便利!

ステップ2で ignored-error-codes.json と loosely-type-checked-files.json というファイルが生成されるのですが,どうやら loosely-type-checked-files.jsonに含まれるファイルの中の ignored-error-codes.json で指定されたエラーを無視するようです.つまり,loosely-type-checked-files.json で指定されたファイルでも ignored-error-codes.json に含まれないエラーが追加されたときはエラーとして検知してくれるようです.

最後に

今回は徐々に直していく方法を検討しましたが,結局他タスクで忙しくなって,放置プレーになりそうなので,しっかりといつまでに終わらせるという期限の設定は必要になると思います.

それに,あえて直さないという選択も状況次第ではありだと思います.3ヶ月後にキャッシュアウトするのに,悠長に型エラーなんて直してられないですから.目の前のお金になる機能を開発しましょう.

いいなと思ったら応援しよう!