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
// Module '"/home/runner/work/TypeScript-Website/TypeScript-Website/utilFunctions"' has no default export.
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,否則會導致開發者開發無報錯感知,但項目啟動一堆報錯問題。
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。