TL;DR

  • JavaScript ファイルの先頭に // @ts-check を書くと、TypeScript に置き換えなくても型チェックを有効にできる。
  • ただしチェックはかなり緩い。最終的なゴールは TypeScript への置き換えなので、JSDoc で完璧に型を付けることに時間をかけない。

内容

@ts-check の位置づけ

TypeScript に移行するとき、JavaScript ファイルの先頭に // @ts-check を追加すると、そのファイルの型チェックを有効にできる。ただし、チェックは非常に限定的で、noImplicitAny をオフにした場合よりも緩い。最終的なゴールは TypeScript に置き換えることなので、JSDoc でコードを完璧に型付けすることに時間をかけない。

よく出るエラーと解決策

宣言されていないグローバル変数

// @ts-check
console.log(user.firstName)
//          ~~~~ Cannot find name 'user'

そのシンボルが別の場所で定義されているなら、型宣言ファイルに書く。

// types.d.ts
interface UserData {
  firstName: string
  lastName: string
}
 
declare let user: UserData

サードパーティのライブラリ

型宣言のパッケージ(@types/...)を別にインストールする必要がある。

npm i --save-dev @types/jquery

DOM

DOM を扱うコードでは、具体的な要素の型が分からずにエラーになることがある(項目75)。

const ageEl = document.getElementById("age")
ageEl.value = "12" // 型エラー: Property 'value' does not exist on type 'HTMLElement'

JSDoc で型アサーションを書いて解決する。

const ageEl = /** @type {HTMLInputElement} */ (document.getElementById("age"))
ageEl.value = "12" // OK

既存の JSDoc が誤っている

/**
 * 要素のサイズを(ピクセル単位で)取得する。
 * @param {Node} el 対象の要素
 * @returns {{w: number, h: number}} 要素のサイズ
 */
function getSize(el) {
  const bounds = el.getBoundingClientRect()
  //                ~~~~~~~~~~~~~~~~~~~~~ Property 'getBoundingClientRect' does not exist
  //                                      on type 'Node'
 
  return { width: bounds.width, height: bounds.height }
  //       ~~~~~ Type '{ width: any; height: any }' is not
  //             assignable to type '{ w: number; h: number }'
}

IDE の言語サービスが提供するクイックフィックスで直せる。ただし、うまくいかない場合もあり、そのときは手で直す。

キーワード