Typescript: error TS2300: Duplicate identifier 'export='.

Created on 29 Nov 2016  路  14Comments  路  Source: microsoft/TypeScript

I used lodash and sequelize in my project and install @types/lodash and @types/sequelize,i get below error when compile.
error TS2300: Duplicate identifier 'export='.
i think @types/sequelize already include @types/lodash in subdirectory,so it has two @types/sequelize in my project,so i want know how to solve the problem?
qq 20161129142242

Question

Most helpful comment

Is there a way to improve the error message when there's duplicate @types resolved and both contain globals

that is the only way to get this error anyways from an @types package. we could add an elaboration of sorts. suggestions welcomed.

Would it help to add a step to DefinitelyTyped PR process to deny future changes to global unless a specific flag is set in the directory (e.g. for node)?

Totally agree. I spoke to @andy-ms about this a few weeks ago. will follow up on that.

All 14 comments

i think @types/sequelize already include @types/lodash in subdirectory

Precisely.

i want know how to solve the problem?

  1. The quick fix is to install a version of @types/sequelize that is semver compatible with that specified by @types/lodash and then npm 3 + won't install it twice (you will need to delete what is there first).

  2. Or you can uninstall your version of @types/sequelize.

  3. specify "compilerOptions"."types" with an array containing exactly the typings you are using and no others.

This is a longstanding problem. npm resolves all semver conflicts this way. It is terrible behavior.

@aluanhaddad thanks reply!
The quick fix is to install a version of @types/sequelize that is semver compatible with that specified by @types/lodash and then npm 3 + won't install it twice (you will need to delete what is there first).
my npm version is 2.15.9
Or you can uninstall your version of @types/sequelize.
i realy want use sequelize with typescript
specify "compilerOptions"."types" with an array containing exactly the typings you are using and no others.
i already try ,but no effect.
finally,i back to typings :disappointed:

@keyiis

i realy want use sequelize with typescript

Sorry, I mispoke. You need to uninstall @types/lodash. Since sequelize comes with @types/lodash, TypeScript will automatically, and in my view unfortunately, include it as if you had installed it yourself except you will not be able to control the version.

You could also try running npm dedupe in npm 2 but it is not likely to help much. If you have to use npm 2 you are probably going to be 馃槩

npm dedupe would be the recommendation here.

@mhegazy Just to check, does this mean TypeScript can't handle sub-dependencies with the same name properly right? If there's a minor version mismatch in types that will result in the same named definition at two levels, but they aren't the same. If so, it'd be nice to fix this as it's a pretty common scenario to run into (sometimes people pin dependencies which would not dedupe, sometimes we legitimately have two major versions in different dependencies which also does not dedupe). I'd be happy to look at doing a PR if it's an issue.

@mhegazy Just to check, does this mean TypeScript can't handle sub-dependencies with the same name properly right?

That is not accurate. my recommendation to use npm dedupe is more of a general remedy. but here are the details..

The core issue for this problem with @types\lodash is https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12773. This change added "global" declarations to lodash, previously it was a "module". I am planning on reverting this, but need to chat with @andy-ms about it first to get more information on the original issue that this change was trying to fix.

A "module" is a file with at least one top-level import or export statement. modules have their own scope and do not pollute the global namespace.

A "global" script is a file that is not a module. these pollute the global scope.

By definition you can have multiple copies of the same module (possibly different versions) in the same compilation with no issues, since each has its own object at runtime and the scopes are isolated. You can not do that with global for instance, one of the multiple definitions will override the other, and result in an unspecified behavior. this is why you get the error "duplicate declaration".

lodash is a module at runtime (since it is a node module), so that is not the issue. the issue is the declaration file in @types\lodash\index.d.ts makes it look to the compiler as if it was a global. So these issues are all definition file authoring bugs. we have tried to fix them as we go, but it is hard to fix them all, hence my general remedy above.

In an ideal world, all declaration files on DefinitelyTyped, except @types\node (and a few others) would be authored as modules (UMD for things that are global as well as modules, e.g. ng/$); but we are not there at the moment.

Hope that clarifies the issue.

@mhegazy Thanks for the clarification, I missed that the DefinitelyTyped version had been turned into a global declaration and it makes sense. Is there a way to improve the error message when there's duplicate @types resolved and both contain globals? If the issue doesn't exist with external modules, there's nothing for me to worry about (again, I was concerned because I missed the global references, I wanted to make sure the submodule can with externals do work).

Would it help to add a step to DefinitelyTyped PR process to deny future changes to global unless a specific flag is set in the directory (e.g. for node)?

Is there a way to improve the error message when there's duplicate @types resolved and both contain globals

that is the only way to get this error anyways from an @types package. we could add an elaboration of sorts. suggestions welcomed.

Would it help to add a step to DefinitelyTyped PR process to deny future changes to global unless a specific flag is set in the directory (e.g. for node)?

Totally agree. I spoke to @andy-ms about this a few weeks ago. will follow up on that.

we could add an elaboration of sorts. suggestions welcomed.

I'll need to review the algorithm for the best action, but if it's complicated or there's multiple solutions you could link to a page on the TypeScript handbook. Something like this, perhaps:

Found a duplicate type for lodash. You will need to resolve this manually using typeRoots or specifying compilerOptions.types.

The resolve is probably too unclear, so a link might be best.

we could say, if we have duplicate definition error, and all declarations are coming from files under the @types (e.g. node_modules\@types), and the folder/files have the same name (e.g. lodash\modules.d.ts in this case), we could recommend using "path" : { "lodash": ["<location of one of the files>"] } }

@mhegazy
The core issue for this problem with @types\lodash is DefinitelyTyped/DefinitelyTyped#12773. This change added "global" declarations to lodash
Many package d.ts may have similar problems,ex: @types\ckeditor

@mhegazy Thank you for the details. They are roughly what I understood to be the case.

Sorry this post is rather long.

TLDR: npm manages JS packages decently enough, but Node's require is what loads them. Unfortunately Node doesn't even respect package.json. It simply assumes that everything is laid out correctly and naively resolves based on a recursive tree walk that is _semver ignorant_. I think this is fundamentally unsound as even nested directories containing distinct "projects" are not bound to get their correct versions. Since these are TypeScript declaration packages, and not even Node modules, npm cannot resolve this. TypeScript is not at fault but simply resolving dependencies from the file system (by default) is bad. I think TypeScript should not use the file system as its source of truth.


When I say that multiple versions are not handled by TypeScript, or that multiple versions are handled poorly, what I mean to say that is that they are handled in the handled in the _NodeJS_ way.

The reason I consider this a problem is that the NodeRequire function does not have any notion of a set of root packages or sibling packages, npm 3 helps in terms of laying out packages in the right way for NodeRequire to usually get things correct but the problem is that, from my limited understanding (please correct me if I am in error 鉂わ笍), there is no notion of an npm package that NodeJS understands. The file system is the source of truth.

I don't generally write fully fledged NodeJS applications, but as a TS/JS user I of course write scripts and I've dabbled in CLI tools with some success (all in TS, because well, why wouldn't I use TS 馃槈).

My opinion is that is unsound behavior on the part of NodeJS because it looks for a file in a directory, and picks the first one it finds (matching by name not version).

Even in a NodeJS project, source control mistakes, or people forgetting to run npm install on checkout, which is a pain, can lead to bugs.

This is why I like JSPM so much. It provides the closest thing JavaScript has to Strongly Named dependencies. It does this by using manifests (package.json and jspm.config.js) to determine what to load, what a project actually is. It goes further determining which dependencies need to be duplicated do to semver conflicts, in a way which is _sound_.

we could say, if we have duplicate definition error, and all declarations are coming from files under the @types (e.g. node_modules@types), and the folder/files have the same name (e.g. lodash\modules.d.ts in this case), we could recommend using "path" : { "lodash": [""] } }

This is a great idea! Would it be at least feasible to do something similar as a quick fix (or even better automatically on installation)? That would make tsconfig.json more like a project root, explicitly mapping dependencies to where they reside.

lodash is a module at runtime (since it is a node module), so that is not the issue. the issue is the declaration file in @typeslodash\index.d.ts makes it look to the compiler as if it was a global. So these issues are all definition file authoring bugs. we have tried to fix them as we go, but it is hard to fix them all, hence my general remedy above.

I think TypeScript should understand and auto resolve this scenario. Since, as you say, lodash is a node module, it will not be loaded twice, but since it declaration file is not, and since that is definitely not something npm will handle, I think this is reasonable.

Having to fix the actual typings package can be a pain. Seems like there should be a way to exclude type dependencies somehow?

Was this page helpful?
0 / 5 - 0 ratings