Hai

Hai

A front-end development engineer who is enthusiastic about full stack.

tsconfig.jsonでallowSyntheticDefaultImportsを慎重に使用してください

背景#

平常ほとんど単体テストを書かないが、昨日 jest を使ってある関数の単体テストを実行したところ、常に三方モジュールが undefined であると報告された。以下は縮小された関数のソースコードである。

// 三方ライブラリをインポートして URL を Object に解析する
import qs from "query-string";
export const getSearch = () => {
  return qs.parse(location.search);
};

この時 jest コマンドを実行すると、コンソールに cannot read parse of undefined というエラーが表示された。最初は jest が外部依存関係を読み込めないのかと思い、サンドボックス環境で実行していた。外部依存関係を読み込むために moduleNameMapper を指定する必要があり、その後の試みはすべて失敗に終わった。

私は理解できず、プロジェクト内で "query-string" ライブラリの参照を全文検索したが、すべてデフォルトインポートの書き方だった。そこでブラウザで getSearch メソッドを呼び出してみたが、エラーは出なかった。

この時、私は node_modules の中で答えを探すしかなかった。驚くべきことに、ソースコードはすべて具名エクスポートの書き方だった。
image.png

まずはインポートの方法を具名インポートに変更し、単体テストを実行してみる。

import { parse } from "query-string";

振り返ってこの問題を考える。なぜプロジェクト内の query-string ライブラリの参照はすべてデフォルトインポートの書き方 import qs from "query-string" で、IDE では tsError の警告がなく、ブラウザでも jsError のエラーが出ないのか?

tsconfig の設定ファイルを見返すと、この設定項目 allowSyntheticDefaultImports を発見した。翻訳すると:合成デフォルトインポートを許可する。名前からして、これが原因のように感じた。

ts の公式サイトでその定義を調べてみる:

image.png

もし allowSyntheticDefaultImports が false の場合

// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
module.exports = {
  getStringLength,
};

// @filename: index.ts
// モジュール '"/home/runner/work/TypeScript-Website/TypeScript-Website/utilFunctions"' にデフォルトエクスポートがありません。
import utils from "./utilFunctions";
const count = utils.getStringLength("Check JS");

はっと気づいた。IDE で ts がエラーを出さなかったのは、デフォルトエクスポートのない外部依存関係をデフォルトインポート方式でインポートすることを許可しているからだった。ブラウザでエラーが出なかったのは、プロジェクトを実行する前に babel がエクスポートのコンパイルを行い、変換されたモジュールコードは以下のようになるからである。

// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
const allFunctions = {
  getStringLength,
};
module.exports = allFunctions;
module.exports.default = allFunctions;

プロジェクトのコードを見返すと、実際にはこのような例がたくさんある。上記の例のように

import React from "react";

解決#

  1. tsconfig の reference 機能を使用して、テストファイルの tsconfig をモジュール化し、この設定項目を false に設定して局所的にコンパイルする。
  2. 具名インポートの方法で外部依存関係を読み込む。
  3. babel コンパイルを行っていないプロジェクトでは、allowSyntheticDefaultImports の使用を厳禁とする。そうしないと、開発者はエラーに気づかずに開発を進めることになり、プロジェクト起動時に多くのエラーが発生する。
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。