This error means your TypeScript compiler found a type definition that was declared twice in the same scope, and the second declaration had different properties than the first.
Here are the most common reasons this happens and how to fix them:
1. Duplicate Imports
You’ve accidentally imported the same type or interface from two different modules, or even twice from the same module.
Diagnosis:
Look at the lines indicated by the error message. If they both point to type declarations, check your import statements around those lines. You’ll likely see the same type being imported multiple times.
Fix:
Remove the redundant import statement.
// Original (problematic)
import { MyType } from './some-module';
import { MyType } from './another-module'; // Or even the same module again
// Fixed
import { MyType } from './some-module';
Why it works: TypeScript’s module system relies on unique declarations within a scope. By removing the duplicate import, you ensure that MyType is defined only once, resolving the conflict.
2. Re-exporting and Importing the Same Type
You might be re-exporting a type from a module and then importing it into the same module, creating a self-referential loop or duplicate declaration.
Diagnosis:
Examine the file where the error occurs. If it’s a re-export file (e.g., index.ts), check if you’re exporting a type that’s also being imported and declared within that same file.
Fix: If you’re re-exporting a type, you don’t need to import it into the same file to re-export it.
// Original (problematic)
// types.ts
import { InternalType } from './internal';
export { InternalType }; // This is fine
export interface InternalType { // This is the problem!
// ...
}
// Fixed
// types.ts
export { InternalType } from './internal'; // Just re-export it directly
Why it works: When you export { InternalType } from './internal';, you’re making InternalType available to other modules without needing to declare it again locally. The second declaration is what causes the TS2717 error.
3. Global Type Declarations Overwritten
If you’re using global type declarations (e.g., augmenting existing types with declare global) and you accidentally redeclare a type within the same global scope.
Diagnosis:
Search for declare global blocks in your project. If you find multiple declare global blocks that attempt to declare or augment the same type (e.g., Window or a custom global type), that’s your culprit.
Fix:
Consolidate all declarations for a specific global type into a single declare global block.
// Original (problematic)
// globals.d.ts
declare global {
interface Window {
myCustomProp: string;
}
}
// another-globals.d.ts
declare global {
interface Window {
myOtherProp: number;
}
}
// Fixed
// globals.d.ts
declare global {
interface Window {
myCustomProp: string;
myOtherProp: number;
}
}
Why it works: Global augmentation in TypeScript requires all additions to a specific global type to be within a single declare global block. Multiple blocks attempting to declare the same interface or type will lead to conflicts.
4. Incorrect Module Augmentation
Similar to global declarations, module augmentation (declare module 'some-module') can cause this if you try to augment the same module multiple times with conflicting declarations.
Diagnosis:
Identify any declare module 'some-module' blocks in your .d.ts files. If you have more than one targeting the same module name and attempting to declare the same interface or type within it, you’ve found the issue.
Fix:
Combine all augmentations for a specific module into a single declare module block.
// Original (problematic)
// module-augmentations.d.ts
declare module 'react' {
interface ComponentProps<T> {
customProp?: string;
}
}
// more-augmentations.d.ts
declare module 'react' {
interface ComponentProps<T> {
anotherCustomProp?: number;
}
}
// Fixed
// module-augmentations.d.ts
declare module 'react' {
interface ComponentProps<T> {
customProp?: string;
anotherCustomProp?: number;
}
}
Why it works: TypeScript expects all modifications to a specific module’s types to be grouped within a single declare module statement. Subsequent attempts to declare the same interfaces within that module will be seen as duplicate declarations.
5. Type Aliases vs. Interfaces Redeclared
You might be using a type alias and then an interface with the same name, or vice-versa, in the same scope, and they have different structures. TypeScript doesn’t allow redeclaring types with different definitions, whether they are interfaces, type aliases, or a mix.
Diagnosis: Look at the error message’s location. If it points to a declaration, check if a type alias or interface with the exact same name already exists in that scope.
Fix: Either rename one of the declarations or merge their properties if they are intended to be the same type.
// Original (problematic)
interface User {
id: number;
}
type User = { // TS2717 error here
name: string;
};
// Fixed (Option 1: Rename)
interface User {
id: number;
}
type UserProfile = { // Renamed
name: string;
};
// Fixed (Option 2: Merge into one interface)
interface User {
id: number;
name: string; // Merged properties
}
Why it works: In TypeScript, an interface and a type alias with the same name in the same scope are treated as separate declarations. If their definitions differ, it results in a conflict. Consolidating into a single, correctly defined type or renaming one resolves this.
6. Using export * and Local Declarations
If you’re using export * from './module' to re-export everything from another module, and then you also declare a type with the same name locally in the current file.
Diagnosis:
Check the file where the error occurs. If it contains export * from '...', look for any local type or interface declarations that have names matching those exported by the referenced module.
Fix: If you’re re-exporting everything, you usually don’t need to declare the same types locally. Remove the local declaration.
// Original (problematic)
// index.ts
export * from './utils'; // This exports `HelperType`
// And then later in the same file:
interface HelperType { // TS2717 error here
// ...
}
// Fixed
// index.ts
export * from './utils';
// Remove the local `interface HelperType`
Why it works: The export * statement brings all exported members from ./utils into the current module’s scope. If you then declare a type with the same name locally, you’re effectively declaring it twice.
The next error you’ll likely encounter if these fixes are applied incorrectly is a module resolution error, where TypeScript can’t find a specific imported file or type.