The TS2528: Duplicate Identifier error means your TypeScript compiler found two things with the exact same name in the same scope, and it doesn’t know which one to use.
This usually happens when you’re importing modules, especially if you’re using default imports or have ambient declarations that conflict with your project’s code. The compiler sees two declarations for the same name and throws its hands up.
Here are the most common reasons you’ll hit this and how to fix them:
1. Accidental Re-export of a Default Import:
You’ve imported a module with a default export, and then you’ve accidentally re-exported it with the same name.
-
Diagnosis: Look at your
importstatements and yourexportstatements in the file where the error occurs. You’ll likely see something like:// SomeModule.ts export default class MyClass { /* ... */ }// AnotherFile.ts import MyClass from './SomeModule'; // ... later in the file ... export { MyClass }; // This is the problematic line if you also import MyClass elsewhereOr even more subtly:
// AnotherFile.ts import MyClass from './SomeModule'; // ... export default MyClass; // If you also had `export { MyClass }` or another `export default MyClass` -
Fix: Remove the redundant export. If you’re just using
MyClasswithinAnotherFile.ts, you don’t need to export it again. If you do need to re-export it for other modules to use, ensure it’s the only export of that name. If the original module has a default export and you want to re-export it as a named export, rename it:// AnotherFile.ts import MyClassDefault from './SomeModule'; // ... export { MyClassDefault as MyClass }; // Renamed during re-export -
Why it works: This clarifies for the compiler that there’s only one
MyClassbeing declared or re-exported from this scope.
2. Conflicting Ambient Declaration Files (.d.ts) and Module Imports:
You have a global ambient declaration (often in a *.d.ts file) that defines a global variable or type, and you’re also importing a module that also exports something with the same name, potentially as a default export.
-
Diagnosis: Search your project for
.d.tsfiles. Look fordeclare varordeclare globalstatements. Compare the names declared there with yourimportstatements.// global.d.ts declare var SomeLibrary: { version: string };// my-code.ts import SomeLibrary from 'some-npm-package'; // This package might also export 'SomeLibrary'The error would be
TS2528: Duplicate identifier 'SomeLibrary'. -
Fix:
- Option A (Preferred): If the ambient declaration is for a library that should be an ES module, remove the ambient declaration. Modern libraries usually provide their own TypeScript definitions.
- Option B: If you need the global, rename the import:
// my-code.ts import SomeLibraryModule from 'some-npm-package'; // Now you can use SomeLibraryModule and the global SomeLibrary separately. console.log(window.SomeLibrary.version); console.log(SomeLibraryModule.someProperty); - Option C: If the ambient declaration is truly global and you want to ensure it’s not shadowed by imports, you might need to configure your
tsconfig.jsonto exclude specific declaration files or adjust your module resolution strategy, though this is less common.
-
Why it works: You’re either removing the conflicting global declaration or creating a distinct name for the imported module, so the compiler only sees one definition for each name.
3. Importing the Same Module Twice with Different Names (and one is default):
You might have imported the same library or module multiple times, perhaps through different paths or with different import styles, leading to a name collision.
-
Diagnosis: Again, examine your
importstatements.// file.ts import MyLib from 'my-library'; import * as MyLibAlias from 'my-library'; // This creates a namespace importIf
my-libraryhas a default export,MyLibwill be that export.MyLibAliaswill be an object whereMyLibAlias.defaultis that same export. The compiler might seeMyLibandMyLib.defaultas potential duplicates in certain contexts, or if you then try to exportMyLibandMyLibAliasseparately. -
Fix: Consolidate your imports. Use only one import style for a given module.
// file.ts import MyLib from 'my-library'; // Just use the default import // Or if you need named exports and the default: import MyLibDefault, { namedExport } from 'my-library'; // Or a namespace import if you need all exports under one umbrella: import * as MyLib from 'my-library';Choose the import style that best suits your needs and stick to it for that module.
-
Why it works: By using a single import statement, you ensure that the module’s exports are resolved and assigned to a single, unambiguous identifier in your scope.
4. Incorrectly Using esModuleInterop or allowSyntheticDefaultImports:
These tsconfig.json options control how TypeScript handles CommonJS modules (which don’t have native export default) when you’re writing ES Module code. Misconfiguration can lead to duplicate identifier issues.
-
Diagnosis: Check your
tsconfig.json. If you haveesModuleInterop: trueorallowSyntheticDefaultImports: trueenabled (and they often should be for modern projects), and you’re still seeing this error, it might be a symptom of the other issues listed above, exacerbated by these settings. The error might appear when importing a CommonJS module that has anexports.default = ...pattern. -
Fix: Ensure
esModuleInterop: trueis set in yourtsconfig.json. This is generally recommended for better compatibility with CommonJS modules.// tsconfig.json { "compilerOptions": { "target": "ES2016", "module": "CommonJS", // or "ESNext", etc. "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }Then, re-evaluate your import statements based on the other points. Often, with
esModuleInterop: true, you can import CommonJS modules as if they had default exports. -
Why it works:
esModuleInterop: trueallows TypeScript to emit code that makes CommonJS modules behave more like ES Modules, creating synthetic default exports where appropriate, which can help resolve certain name clashes by standardizing how module exports are accessed.
5. Global Variables Defined in Multiple Files (Non-Module Context):
If you’re not using modules (i.e., you don’t have import or export at the top level of your files, and module in tsconfig.json is set to "none"), you might define global variables in different script files that are loaded in a specific order.
-
Diagnosis: Look for files without top-level
import/exportthat declare variables usingvarorlet(thoughvaris more prone to global redefinition issues).// script1.ts (compiled to script1.js) var GLOBAL_CONFIG = { setting: 'abc' };// script2.ts (compiled to script2.js) var GLOBAL_CONFIG = { setting: 'xyz' }; // Error if script1.js and script2.js are loaded together -
Fix: Transition to a module system. Even if you’re building for the browser, use module bundlers like Webpack or Parcel and set
module: "ESNext"(or similar) intsconfig.json. This ensures that variables are scoped to their respective modules and don’t leak globally unless explicitly exported. If you must use global scripts, ensure each global variable is defined only once. -
Why it works: Modules provide encapsulation. Variables declared within a module are local to that module by default, preventing accidental redefinition in other modules.
6. Typings for Libraries That Don’t Export Defaults:
Sometimes, a library might not have a default export, but its @types package might incorrectly provide one, or you might be trying to import it as a default export when you shouldn’t.
-
Diagnosis: Check the library’s actual export structure (if possible from its documentation or source) and compare it with how you’re importing it and what the corresponding
.d.tsfiles suggest.// file.ts import SomeLib from 'some-library-without-default'; // Error -
Fix: Import it using a named import or a namespace import, depending on its structure.
// file.ts import { SomeLib } from 'some-library-without-default'; // If it has a named export 'SomeLib' // OR import * as LibNamespace from 'some-library-without-default'; // If you want all exports under LibNamespaceIf you suspect the typings are wrong, you might need to create a local declaration file (
.d.ts) to correct it, or report an issue to the library’s maintainers. -
Why it works: You’re aligning your import statement with the actual way the module exports its members, avoiding the compiler’s confusion about a non-existent default export.
After fixing these, the next error you’ll likely encounter is TS2307: Cannot find module '...' if you’ve removed a declaration that was actually needed, or a type error if the underlying logic was flawed.