为啥 Typescript 在转译代码中将 .default() 添加到类构造函数中?

Posted

技术标签:

【中文标题】为啥 Typescript 在转译代码中将 .default() 添加到类构造函数中?【英文标题】:Why Typescript adds .default() to class constructor in transpiled code?为什么 Typescript 在转译代码中将 .default() 添加到类构造函数中? 【发布时间】:2019-09-29 21:21:40 【问题描述】:

我在 TS 中有这段代码,用于在 Express 中创建 ConnectRoles 中间件的实例:

let user = new ConnectRoles(config);

这是中间件期望能够初始化的,对构造函数的简单调用,但是在转译后,生成的 javascript 代码如下所示:

let user = new connect_roles_1.default(config);

我正在使用以下方法在 TS 中导入此类:

import ConnectRoles from "connect-roles";

翻译成:

const connect_roles_1 = require("connect-roles");

在 JS 中,我实例化/导入类的方式是否可能是这里的问题?我可以手动删除导致 JS 代码错误的“默认”方法,但这违背了使用转译器的目的,特别是如果这样的事情开始更频繁地发生。

还有一件事,这是我的 tsconfig.json:


  "compilerOptions": 
      "baseUrl": ".",
      "paths":  "*": ["types/*"] ,
      "target": "es2015",
      "module": "commonjs",
      "moduleResolution": "node",
      "isolatedModules": false,
      "jsx": "react",
      "experimentalDecorators": true,
      "emitDecoratorMetadata": true,
      "declaration": false,
      "noImplicitAny": false,
      "noImplicitUseStrict": false,
      "removeComments": true,
      "noLib": false,
      "preserveConstEnums": true,
      "suppressImplicitAnyIndexErrors": true,
      "outDir": "app",
      "sourceMap": true,
      "watch": true
  ,
  "exclude": [
      "node_modules",
      "typings/browser",
      "typings/browser.d.ts",
  ],
  "compileOnSave": true,
  "buildOnSave": true,
  "atom": 
      "rewriteTsconfig": false
  

任何想法将不胜感激,谢谢!

【问题讨论】:

【参考方案1】:

正如 Tobiq 所说,import ConnectRoles from "connect-roles" 正在尝试导入默认导出。但是,您尝试导入的模块不使用默认导出;相反,它使用module.exports = ConnectRoles

以下是三种不同的导入样式以及它们产生的编译结果:

import ConnectRolesImport from 'connect-roles';
const connectRolesImport = new ConnectRolesImport(); // error!

import * as ConnectRolesImportAll from 'connect-roles';
const connectRolesImportAll = new ConnectRolesImportAll();

import ConnectRolesRequire = require('connect-roles');
const connectRolesRequire = new ConnectRolesRequire();

编译结果:

var connect_roles_1 = require("connect-roles");
var connectRolesImport = new connect_roles_1["default"]();

var ConnectRolesImportAll = require("connect-roles");
var connectRolesImportAll = new ConnectRolesImportAll();

var ConnectRolesRequire = require("connect-roles");
var connectRolesRequire = new ConnectRolesRequire();

这是TypeScript team members 之一,讨论import xxx as...import xxx = require... 语法之间的区别。那和这个答案的 cmets 将帮助您选择使用哪个。

【讨论】:

require 在打字稿中未定义。 ***.com/questions/12742082/… @Tobiq 如果我们编译时没有将module 设置为commonjs,就会发生这种情况。问题是询问一个 express 应用程序,因此假设使用commonjs 作为模块系统是合理的。 这是可行的。 Typescript 扩展了实验模块,其中 require 已弃用。 感谢您的回答,两者都很棒,我都赞成,但不得不将 Shaun Luttin 的回答标记为答案,因为他对我的情况更加具体。还要感谢 Tobiq,您的回答帮助我更好地了解如何处理打字稿文件与节点文件中的导入和导出。谢谢大家。【参考方案2】:

您应该将 typescript 文件视为导出对象的模块。


import x, y, z from "module" 是您访问这些导出的方式。

当您使用import x from "module" 时,实际上您只是从模块中导入default

import x from "module" 只是import default as x from "module" 的别名

module 本身并不是一个出口。这就是为什么您仍然可以导入其他导出:

import default, x, y, z from "module"


模块.ts

export const x = /*...*/;
export const y = /*...*/;
export const z = /*...*/;
export const default = /*...*/;

过去,您可以像这样导出一个默认值:

module.exports = /*...*/;

但是,现在您应该严格按照以下形式考虑导出:


   exportName: /*...*/,
   default: /*...*/


许多模块仍然使用旧约定导出默认值:module.exports = /*...*/;

在这种情况下,您可以使用import * as x from "module"; 导入它们

【讨论】:

以上是关于为啥 Typescript 在转译代码中将 .default() 添加到类构造函数中?的主要内容,如果未能解决你的问题,请参考以下文章

您如何将伊斯坦布尔代码覆盖率与转译的 Typescript 一起使用?

TypeScript 转译的文件是不可执行的

Angular2 的 TypeScript 到 JavaScript 转译器

vs 代码不转译 ts 文件

emitDecoratorMetadata 及其在转译代码中的重要性

如何避免 Typescript 转译 Jest __mocks__