TypeScript Re-exporting CJS module with export = from ESM via export * causes type error

cwxwcias  于 6个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(43)

Bug报告

当通过export *在ES模块中重新导出类型声明使用export =的cjs包时,TypeScript会引发诊断。

🔎 搜索词

  • "'export =' 不能与 'export *' 一起使用"

🕗 版本 & 回归信息

5.0.0-dev.20221216

⏯ Playground链接

N/A - 多个文件

💻 代码

  1. mkdir scratch && cd scratch
  2. npm init -y
  3. npm i react @types/react typescript@next
  4. tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "moduleResolution": "NodeNext",
    "strict": true
   }
}
  1. react.mts
export * from "react";

// notice this import is fine and does not error
import { useCallback } from "react";
  1. main.mts
import { useCallback } from "./react.mjs";
console.log(useCallback);

🙁 实际行为

尝试进行类型检查和发出:

> npx tsc
main.mts:1:10 - error TS2305: Module '"./react.mjs"' has no exported member 'useCallback'.

1 import { useCallback } from "./react.mjs";
           ~~~~~~~~~~~

react.mts:1:15 - error TS2498: Module '"V:/scratch-npm/node_modules/@types/react/index"' uses 'export =' and cannot be used with 'export *'.

1 export * from "react";
                ~~~~~~~

Found 2 errors in 2 files.

Errors  Files
     1  main.mts:1
     1  react.mts:1

它将发出,所以尝试运行它并查看它是否有效:

> node main.mjs
[Function: useCallback]

🙂 预期行为

应该可以正确进行类型检查,因为这在运行时是有效的,并且export =与具有单个module .exports = ...赋值的运行时代码匹配。

lpwwtiir

lpwwtiir1#

所以,据我所知,我们不允许这样做,因为 export * 可能从 cjs-y 中定义的 export= 模块中拉取什么含义是不清楚的。现在,在 node16 中,我们有一个相当规范的答案,即语法检测到的 cjs 命名导出将被重新导出(我们可以假设这些是在声明文件中的命名成员)。向下级,这仍然有点不清楚 - 它是否会从分配的模块对象中剥离调用和构造签名?__exportStar 帮助程序有一个行为,但它可能不是人们期望的那种(尤其是没有 allowSyntheticDefaultImportsesModuleInterop 的情况下),据我所知,这就是为什么我们有这个错误,即 omega old。完全删 debugging 误只会使 3 个测试失败,但这些测试确实引发了一些奇怪的情况,因为你可以 export= 很多东西,比如

declare module "interface" {
        interface Foo {
            x: number;
            y: number;
        }
        export = Foo;
    }

或者,更有趣的是

declare module "variable" {
        var Foo: {
            a: number;
            b: number;
        }
        export = Foo;
    }

即使在现代的 node 中,这也可能令人困惑 - 比如

// @filename: a.ts
export = { a: 0 }
    
// @filename: b.ts
export * from './a';

可能不清楚 export * from './a'; 没有重新导出任何内容,因为 a.ts 没有语法提升的成员,而且模块作为 default 并不包含在重新导出的成员中(因为默认值永远不会被包括)。
所以虽然我们 可以 删 debugging 误,但我认为它可能仍然指出了当人们跨越模块系统边界时可能出现的问题。

bzzcjhmw

bzzcjhmw2#

可能不清楚从'./a'导出的*;没有重新导出任何内容,因为a.ts没有语法上提升的成员,而且模块默认值不包含在重新导出的成员中(因为默认值永远不会被包含)。
所以虽然我们可以移 debugging 误,但我认为它仍然可能指出人们跨越模块系统边界时可能出现的问题。
有很多情况,一个cjs包用export =描述,可能无法与es模块中的命名导入一起工作,但TypeScript允许你编写一个命名导入。我认为这也应该适用于重新导出?

相关问题