【问题标题】:How does babel-loader / tsc compiler know NOT to import a package when it's being imported just for the types?当只为类型导入包时,babel-loader / tsc 编译器如何知道不导入包?
【发布时间】:2020-07-29 15:48:57
【问题描述】:

我目前正在我的项目中实现 Typescript。

我发现了一些奇怪的东西。

您可以在下面的 App.tsx 文件中看到,我必须 import firebase from "firebase/app" 才能访问 firebase.app.App 类型。

App.tsx

import React from "react";
import firebase from "firebase/app";

interface App_PROPS {
  firebase: firebase.app.App | null;
};

firebase.initializeApp({});

const App: React.FC<App_PROPS> = () => {
  return(
    <div>App</div>
  )
};

export default App;

而且我认为这会成为我项目中的一个错误,因为由于我执行 SSR,因此导入 CANNOT 发生在我的服务器代码上,因为firebase/app 不打算用于服务器。这就是为什么firebase 包被传递给props,顺便说一句。

但令我惊讶的是,包根本没有导入:

当我使用 babel-loader(通过 webpack)将它与 babel 一起编译时,这就是我得到的:

App.js - 转译为 babel

var _react = _interopRequireDefault(require("react"));

// (...) SOME OTHER CODE
// I WILL NOT POST THE FULL CODE HERE
// BUT "firebase/app" WAS NOT IMPORTED

当我使用 tsc src/App.tsx 编译它时

App.js - 使用 tsc 转译

"use strict";
exports.__esModule = true;
var react_1 = require("react");
;
var App = function () {
    return (<div>App</div>);
};
exports["default"] = App;

// "firebase/app" WAS NOT IMPORTED

谁能向我解释在这种情况下发生了什么?我很高兴转译器不导入包,但这是为什么呢?

是因为我只使用 interface {} 内的包吗?那么,在为 typescript 转换之后,该接口将消失(因为它在 JS 中不存在)并且该包将被某些tree-shaking 算法丢弃?

OBS:我也尝试过相同的代码,但这次调用 firebase.initializeApp(),这是 firebase 包中的一个方法。在这种情况下,firebase/app 包被导入到 App.tsx 文件的转译版本中,这是有道理的。

【问题讨论】:

    标签: typescript firebase webpack tsc


    【解决方案1】:

    这一切都归结为这个导入是否被用作一个值?还是只打字?

    我会解释:

    以此为例:

    import firebase from "firebase/app";
    

    如果你使用firebase.initializeApp() - 你使用它的值,从 typescript 编译生成的 javascript 需要提供 initalizeApp 函数并让它在运行时运行 - 在编译结束后。这意味着它需要访问 firebase 导入,因此 typescript 编译不会剪切此导入,然后 webpack 将其传输到 __webpack__require .

    另一方面,如果你使用firebase: firebase.app.App | null; - 你使用它的类型。 您对打字稿编译器说:“当您键入安全的 firebase 属性时,请确保其类型为 firebase.app.App。” - 在这种类型的安全检查之后,不再需要任何与 firebase 相关的东西。

    当 typescript 编译文件时,它会检查它是否使用来自给定导入的 only Types。如果是这样,它会削减该导入。


    旁注:

    在 Typescript 3.8 中引入了 import type 关键字。

    它让你定义

    import type firebase from "firebase/app";
    

    这意味着此导入只能用于类型。如果您尝试firebase.initializeApp()构建将失败。 如果您担心未来的开发人员也将此导入用作值,那么这对于您的场景来说将是经典的。

    【讨论】:

      猜你喜欢
      • 2014-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      相关资源
      最近更新 更多