在 commonjs 和 ejs 之间共享文件,Typescript 不是 commonjs 文件上的 module.ts(2306)

Sharing file between commonjs and ejs, Typescript is not a module.ts(2306) on commonjs file

背景

我有一个文件需要在两个存储库之间共享。该文件包含一个对象。

我知道如果我使用 modules.export = myObject 它只适用于 commonjs 仓库(仓库 A),如果我使用 export = myObjectexport default myObject 它只适用于 ES6 仓库(回购 B)。

问题:

  1. 是否可以使同一个文件适用于两个系统?我尝试了 export = modules.export = myObject 或任何其他组合,但 none 有效。

  2. 如何在 ES6 存储库中导入 commonjs 版本? 我尝试将其保留为 commonjs modules.export = myObject 文件,但在 Repo B 中,当我做 import foo from "path/to/file" 它一直在哭泣以下信息。当我将它更改为 export = myObject 时它就消失了,但它对 Repo A 不起作用。

File '/path/to/file.ts' is not a module.ts(2306)

备注

  1. 我发现 "esModuleInterop": true 在我的 tsconfig.json 中设置,但无论我做什么,(tsconfig.json 中的任何 "module" 值,转向allowSyntheticDefaultImports) 它不起作用。我不断收到相同的 2306 错误。
  2. 正如我在评论中提到的,可以认为该文件包含一个静态对象。 (例如 {a: 5, b: 8};

tsconfig.json

我正在接触的回购协议 A 中的部分是 config file for Quasar,它是在 vanilla JS 中。

Repo B 是Typescript/Node项目,其中tsconfig.json的相关部分是:

"compilerOptions": {
        "baseUrl": ".",
        "esModuleInterop": true,
        "experimentalDecorators": true,
        "module": "commonjs",
        "moduleResolution": "node",
        "outDir": "dist",
        "strict": true,
        "sourceMap": true,
        "target": "es6",
        ...

我找到了一个解决方案,但是 commonjs 领域的导入语法不是最好的,但我希望它对你有用。

除了指定 commonjs 和 es6 样式导入之外,您没有提供有关项目设置方式的任何信息,因此我在这里不顾一切。同样值得注意的是,虽然包含的文件有效,但在使用 commonjs 样式的导入时,它们被键入而不是保留它们的打字稿类型(我无法使用 commonjs 样式的导入(需要)进行键入 - 我没有使用过这个导入语法有一段时间所以正确的 tsconfig.json 选项让我逃脱了)。


我将共享代码移到它自己的项目中并使用以下 tsconfig 设置对其进行编译:

共享 tsconfig.json:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "ES5",
        "lib": [ "ES5" ],
    }
}

Shared.ts:

export default {'a': 1, 'b': 2};

Shared.js(输出):

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = { 'a': 1, 'b': 2 };

(注意这个输出是commonjs风格,因为ES6兼容commonjs文件)


直接使用 require 时需要引用导入文件中的 .default 变量:

commonjs.ts

var val = require("../shared/shared").default;

console.log(val);

但是,如果您配置为可以将 ES6 样式的导入和输出写入 commonjs,则可以改用以下语法(这将为您提供输入信息):

commonjs.ts

import val from "../shared/shared";

console.log(val);

以上两个文件都是使用以下 tsconfig 编译的:

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "lib": [ "es5" ],
        "types": ["node"]
    }
}

ES6 导入非常简单:

es6.ts

import shared from "../shared/shared";

console.log(shared);

tsconfig.json:

{
    "compilerOptions": {
        "module": "ES6",
        "target": "es6",
        "lib": [ "es6" ]
    }
}

我暗暗怀疑这并不能 100% 解决您的问题,但我需要您为每个项目设置 tsconfig 设置作为您为每个项目使用的打字稿编译器的版本,以便更准确回答。

我进行了更多实验并提出了您可能更喜欢的另一个解决方案。

我仍然没有弄清楚如何在 common-js 样式的导入上进行输入,但如果 运行 并且不会导致编译器错误,导入确实有效。


我将共享代码移到它自己的项目中,并使其编译到不同的目录。这是因为如果导入打字稿文件,“esModuleInterop”标志不起作用,所以我将 javascript 文件和支持的 .d.ts 文件编译到另一个目录,以便源 .ts 文件不不会引起冲突。

共享 tsconfig.json:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "ES5",
        "lib": [ "ES5" ],
        "declaration": true,
        "outDir": "../sharedOut"
    }
}

分享d.ts:

export = {'a': 1, 'b': 2};

在输出文件夹中你应该得到:

Shared.js:

"use strict";
module.exports = { 'a': 1, 'b': 2 };

共享。d.ts

declare const _default: {
    a: number;
    b: number;
};
export = _default;

这会使您的 commonjs 导入看起来像这样:

commonjs.ts

var val = require("../sharedOut/shared");

console.log(val);

或者(如果你可以使用 ES6 风格的导入但需要输出是 commonjs):

import val from "../sharedOut/shared";

console.log(val);

以上两个文件都是使用以下 tsconfig 编译的:

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "lib": [ "es5" ],
        "types": ["node"],
        "esModuleInterop": true
    }
}


ES6 导入(再次)非常简单:

es6.ts

import shared from "../shared/shared";

console.log(shared);

tsconfig.json:

{
    "compilerOptions": {
        "module": "ES6",
        "target": "es6",
        "lib": [ "es6" ],
        "esModuleInterop": true
    }
}


同样,如果这不能解决您的问题,我需要更多信息才能继续。我需要你对每个项目的 tsconfig 设置作为你为每个项目使用的打字稿编译器的版本,以便做出更准确的答案。

我刚发现只要文件是 .json 格式正确 JSON 的文件,就可以在 ES6 (import) 和 CommonJS (require).

Per (and this article),对于 ES6,您需要在 tsconfig.json 中启用 "resolveJsonModule": true,,然后您可以同时拥有两种格式的内容。

因此,如果文件 content.json 具有以下内容(没有注释或其他任何内容):

{
   "age": 34
}

然后我们将...

import * as jsonContent from "../../content.json"

console.log(jsonContent.age); // prints out 34

以及

const jsonContent = require("../../content.json");

console.log(jsonContent.age); // prints out 34

他们都成功打印出了内容!