TypeScriptでFetch APIを利用するとき、 Node.js v18から利用できるデフォルトのFetch APIと、それ以前のバージョンのnode-fetchを利用したfetchで挙動が違った話。


問題のコード

before.ts
const apiRequest = (): Promise<Response> =>
  fetch(`<ENDPOINT_URL>`, {
    method: "GET",
  }).then((response) =>
    response.status === 200
      ? response.json()
      : Promise.reject(
          new Error(`fetch failed: response.status=${response.status}`)
        )
  );

もともと動いていた上記コードを、Node.jsv18の環境からv14の環境に移行して実行したらエラーが出た。

エラー内容

Type 'Promise<unknown>' is not assignable to type 'Promise<Response>'.
Type 'unknown' is not assignable to type 'Response'.

response.json()の返り値がPromise<unknown>であることが原因

Node.jsv18fetch()が返す値はany型であった。

修正後

after.ts
const apiRequest = (): Promise<Response> =>
  fetch(`<ENDPOINT_URL>`, {
    method: "GET",
  }).then((response) =>
    response.status === 200
      ? (response.json() as Promise<Response>)
      : Promise.reject(
          new Error(`fetch failed: response.status=${response.status}`)
        )
  );
型アサーションでResponse型であることを明示することで暫定対応。

知見

any型はTypeScriptが型のチェックを行わないので意図しないランタイムエラーの原因となるので、避けるべき。

参考文献