This TypeScript error occurs when you try to declare the same property with different types in interface merging, declaration merging, or module augmentation. The error ensures type consistency across your codebase by preventing conflicting type definitions for the same property.
The "Subsequent property declarations must have the same type" error is TypeScript's way of enforcing type consistency when you declare the same property multiple times. This typically happens in three scenarios: 1. **Interface Merging**: When you declare the same interface multiple times across different files or in the same file, TypeScript automatically merges them. If you try to give the same property different types in these declarations, TypeScript raises this error. 2. **Declaration Merging**: When you extend types, namespaces, or classes and attempt to override a property with a different type. 3. **Module Augmentation**: When you try to add properties to existing types from third-party libraries or built-in types with incompatible types. TypeScript requires that all declarations of the same property have identical types to maintain type safety. This prevents runtime errors where code might expect one type but receives another.
First, search your codebase for duplicate interface declarations. Look for interfaces with the same name declared in multiple places:
// File 1: user.ts
interface User {
id: string;
name: string;
}
// File 2: admin.ts
interface User {
id: number; // ERROR: Different type than File 1
role: string;
}Use your IDE's search functionality or command-line tools like grep to find all declarations of the problematic interface.
If you find duplicate interface declarations, consolidate them into a single interface definition. You can use interface extension instead of duplicate declarations:
// Base interface
interface User {
id: string;
name: string;
}
// Extended interface (if you need additional properties)
interface AdminUser extends User {
role: string;
permissions: string[];
}Or create a union type if you need different property types:
type User = {
id: string;
name: string;
} | {
id: number;
name: string;
isLegacy: boolean;
};If you're augmenting modules (like adding properties to third-party types), ensure you're using compatible types:
// Original type in library
declare module 'some-library' {
interface Config {
timeout: number;
}
}
// Your augmentation (WRONG - causes error)
declare module 'some-library' {
interface Config {
timeout: string; // ERROR: Different type
}
}
// Your augmentation (CORRECT - same type)
declare module 'some-library' {
interface Config {
retries: number; // OK: New property
timeout: number; // OK: Same type as original
}
}If you need to change a property type, you may need to create a wrapper type instead of augmenting.
Be cautious with intersection types (&) as they can create never types for conflicting properties:
interface A {
value: string;
}
interface B {
value: number;
}
type C = A & B;
// Type of C.value is 'never' (string & number = never)
// Instead, use a union type or redesign your types
type BetterType = {
value: string | number;
} | {
stringValue: string;
numberValue: number;
};If the error involves third-party libraries, check if you have conflicting type definitions:
1. Check your node_modules/@types directory for duplicate type definitions
2. Look for @types/package-name conflicts in your package.json
3. Check if you're importing types from multiple versions of the same package
You can use npm ls @types/package-name or yarn why @types/package-name to check for duplicate type definitions.
If you find conflicts, you may need to:
- Remove duplicate type packages
- Use type resolution aliases in your tsconfig.json
- Create declaration merging with proper type compatibility
If you need an object type that can have properties of different types, use an index signature with a union type:
// Flexible object type
interface FlexibleObject {
[key: string]: string | number | boolean;
// These are OK because they match the index signature
name: string;
age: number;
active: boolean;
}
// Type-safe approach with discriminated union
type User =
| { type: 'admin'; permissions: string[]; id: string }
| { type: 'guest'; sessionId: string; id: number };This approach maintains type safety while allowing property type variation.
## Advanced Scenarios and Edge Cases
### Declaration Merging with Namespaces
When using namespace declaration merging, the same type consistency rules apply:
namespace MyLib {
export interface Config {
debug: boolean;
}
}
namespace MyLib {
export interface Config {
debug: string; // ERROR: Different type
}
}### Global Augmentation
When augmenting global types (like adding to Window or Document), ensure type consistency:
// In one file
declare global {
interface Window {
myApp: { version: string };
}
}
// In another file (ERROR)
declare global {
interface Window {
myApp: { version: number }; // Different type
}
}### Conditional Types and Mapped Types
When using advanced TypeScript features, type conflicts can be more subtle:
type WithId<T> = T & { id: string };
interface User {
name: string;
id: number; // This will conflict if WithId<User> is used
}
// The conflict happens when:
type UserWithStringId = WithId<User>; // id: string & number = never### Type Inference Conflicts
Sometimes the error appears due to TypeScript's type inference:
// TypeScript infers { x: number }
const obj1 = { x: 1 };
// Later declaration (ERROR if types don't match)
interface MyType {
x: string; // Conflict with inferred type
}## Performance Considerations
- Interface merging doesn't affect runtime performance
- Complex type operations (intersections of large types) can slow down compilation
- Consider using type aliases instead of interfaces if you don't need declaration merging
## Migration Strategies
When refactoring code with these errors:
1. Use the --noImplicitAny flag to catch type issues early
2. Gradually fix errors starting with the most frequently used interfaces
3. Consider creating type versioning for breaking changes
4. Use deprecation warnings in JSDoc comments during migration
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript