Typescript: TS4023:导出的变量“ X”具有或正在使用外部模块“ a / file / path”的名称“ Y”,但无法命名

创建于 2015-11-18  ·  24评论  ·  资料来源: microsoft/TypeScript

我正在尝试创建一组外部TypeScript模块,如下所示:

// ClassA.ts
export default class ClassA {
  public method() { return true; } 
}

// ModuleB.ts
import ClassA from './ClassA';
var moduleB = {
  ClassA: ClassA
};
export default moduleB;

// ModuleA.ts
import moduleB from './ModuleB';
var moduleA = {
  moduleB: moduleB
}
export default moduleA;

想法是将其编译并作为库提供。 计划是库的使用者将实例化ClassA实例,如下所示:

import moduleA from './ModuleA';
var anInstance = moduleA.moduleB.ClassA();

看起来好像正在编译为预期的JS,但是我遇到了一个错误编译器错误,我一直在努力寻找有关的详细信息。

Using tsc v1.6.2
.../src/ModuleA.ts(3,5): error TS4023: Exported variable 'moduleA' has or is using name 'ClassA' from external module ".../src/ClassA" but cannot be named.

这里有人可以阐明这个问题吗? 我想做的事有意义吗?

Question

最有用的评论

FWIW通常会在Stack Overflow上获得更快的答案,但是我们在这里提出了措辞明确的问题。

这里的问题是您使用的是--declaration标志,但是没有为编译器提供完成其工作的方法。

尝试发出ModuleA.d.ts ,编译器需要编写一个表示模块形状的对象类型文字(例如{ moduleB: { classA: *mumble?* } } )。 但是作用域中没有一个直接指向classA ,因此它的类型为“无法命名”,并且存在错误。

如果将importClassAModuleA.ts ,错误应该消失了。

所有24条评论

哦-如果这不是问这个问题的合适地点。 请让我知道,我很乐意将其发布在其他媒体上。

FWIW通常会在Stack Overflow上获得更快的答案,但是我们在这里提出了措辞明确的问题。

这里的问题是您使用的是--declaration标志,但是没有为编译器提供完成其工作的方法。

尝试发出ModuleA.d.ts ,编译器需要编写一个表示模块形状的对象类型文字(例如{ moduleB: { classA: *mumble?* } } )。 但是作用域中没有一个直接指向classA ,因此它的类型为“无法命名”,并且存在错误。

如果将importClassAModuleA.ts ,错误应该消失了。

嗨,瑞安(Ryan)-感谢您的建议RE堆栈溢出和建议-将导入添加到ModuleA按预期进行编译。

这里有一点背景-我的目标确实是为我的外部模块生成声明。 (我相信还不能正常工作吗?#5039?)这种导入可能是完全必要的,但是对于ModuleA需要导入moduleB已经导出的符号,这有点奇怪。 结果是每次我将添加到ModuleB的对象导出时,都需要将导入添加到ModuleA -直接:

import {moduleB} from './moduleB';
import {ClassA} from './ClassA';

或通过ModuleB (以减少在两个地方为ClassA指定的路径):

import {moduleB, ClassA} from './moduleB';

我对TS编译器知之甚少-所以也许我说的是完全不现实的,但是起初以为编译器可以推断ModuleB会导出一个带有N个符号的对象,因此ModuleA需要这些符号吗? ModuleB的导入信息已经存在- ModuleA使用该信息吗? 还是那样是不可能的,因为对于进口ClassA完全是内部ModuleB ,所以没有办法编译器可以推断出该类型ClassA创建定义时, ModuleA

再次感谢您抽出宝贵的时间回答。 我已经解决了我的问题,因此以上内容主要是出于好奇-无需急于回答。

我不确定你在说什么。 此提案中的ModuleA.d.ts应该是什么样?

编译器在发出声明时不会添加用户代码中不存在的依赖项(即import语句)。 您得到的错误意味着编译器正在尝试为导出的声明编写类型注释,但不能这样做。 这可能有两个原因之一,要么名称不可访问(即无法在当前模块中导入),要么存在覆盖原始声明的声明。

在这两种情况下,您的解决方法都是添加显式类型注释,如果添加任何类型注释,它将在输出中逐字显示; 另一个选择是确保名称是可访问的,即,您已经导入到模块,并且您了解这对于导入模块的用户意味着什么。

@mhegazy说:

编译器在发出声明时不会添加用户代码中不存在的依赖项(即import语句)。

问题是我并非总是需要代码中的import语句(显然,因为它在没有--declarations情况下可以工作),并且包含它们很吵,导致诸如tslint类的事情抱怨“未使用的导入”。 我可以看到为什么您不希望编译器将依赖项添加到发出的javascript中,但是将它们添加到发出的声明中又有什么问题呢?

请随时记录问题以跟踪此建议。 合理的理由是导入是对依赖项的声明,除非您指示这样做,否则编译器不应为您创建一个声明。

这可能会产生更深的后果。

考虑moduleA -> moduleB -> moduleC -> moduleD

moduleB是需要执行import { ABC } from 'moduleA'来解决此问题的一个。

moduleC使用moduleB并导出其签名时,它再次编译失败,因为moduleB需要ABCmoduleA但是这次moduleB没有导出。

这意味着:

  1. moduleC必须具有moduleA的硬依赖性并导入ABC
  2. moduleB需要导入,还需要重新导出ABC ,然后moduleC导入它。

如果moduleD做类似的事情,那么基本上您需要了解整个依赖链。

我无法对此进行测试以证明是这种情况,因为我正在使用typings并且有一个问题阻止了我,所以: https :

编辑:我能够重现它,实际上我的moduleD需要引用moduleA来进行导入。
在我的示例中:

  • moduleA => redux
  • moduleB => redux-thunk
  • moduleC =>在redux-thunk之上的自定义代码
  • moduleD =>一些图书馆
  • ABC => Dispatch接口在redux

我有@unional描述的相同问题

请重新打开此问题, @unional概述的问题非常现实,这使得在使用与我们要重新导出的原始模块相同的类型的同时,很难在库顶部添加任何中间/辅助库。

发出https://github.com/Microsoft/TypeScript/issues/9944跟踪在声明发出阶段添加导入。

谢谢!

添加导入的问题在于,对于noUnusedLocals ,编译器将抱怨未使用该类型。 我可以添加一个显式的类型注释,但是这样我就不会得到推断。 例:

class Whatever {
  fetch(uri: string): Promise<void> { }
  ensureFetched = MemoizedFunction<(uri: string) => Promise<void>> = memoize((uri: string) => this.fetch(uri))
}

我想省略ensureFetched类型注释

我找到了解决方法:
在tsconfig中: include: [ ..., "node_modules/@your_scope/your_library" ]
祝你好运,玩得开心:smiley:

@ salim7会减慢您的编译时间(因为您正在重新编译本应已编译的库),并迫使您对目标库使用严格性设置的最小公分母。

@mhegazy在下一个场景中重现了该问题:

import * as Foo from "./Foo";

export class Bar {
    baz = new Foo.Baz(); // Compiler forgot "Foo." prefix in the type, and throws this error, because "Baz" without perfix is not imported.
    getBaz() { // All the same
       return new Foo.Baz();
    }
}

解决方案是显式指定类型:

import * as Foo from "./Foo";

export class Bar {
    baz: Foo.Baz = new Foo.Baz(); // ok
    getBaz(): Foo.Baz { // ok
       return new Foo.Baz();
    }
}

我无法使用上面的示例来复制它。 请提交一个新的错误,并提供更多背景信息以重现该问题。

@PFight谢谢! 对我来说就是那样!

我刚刚在使用时遇到了这个问题:

export { IMyInterface } from './file'
````

The solution was to do this:
```ts
import { IMyInterface } from './file'
export { IMyInterface }

但这确实不是必需的。

有人知道如何处理noUnusedLocals吗?

@yordis // @ts-ignore

@pelotom是的,这完全是我的错,

我在想一件事,然后写了另一件事。

Typescript是否解决了noUnusedLocals和声明之间的问题?

我目前的解决方法,这让我感到非常痛苦,

import {SomeInterface} from "./SomeFile";

const _dummySomeInterface : undefined|SomeInterface = undefined;
_dummySomeInterface;

//Code that implicitly uses SomeInterface

避免使用noUnusedLocals ,并且尽可能允许通用接口的类型推断。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

wmaurer picture wmaurer  ·  3评论

dlaberge picture dlaberge  ·  3评论

DanielRosenwasser picture DanielRosenwasser  ·  3评论

manekinekko picture manekinekko  ·  3评论

seanzer picture seanzer  ·  3评论