You are utilizing a functionality in TypeScript known as declaration merging. The issue arises when non-function members of interfaces are not unique. In such cases, they must have the same type (refer to the official documentation).
An interesting point: Employing declare module 'foo'
for importing and merging existing objects is referred to as module augmentation, which falls under declaration merging. It is possible to merge two interfaces with identical names in the same file.
A Potential Resolution
As combining members of different types through declaration merging is not feasible, one alternative could be defining a new type explicitly.
/// animal.ts
export interface Animal {
name: string
age: number
birthday: string // goal: represent birthday as a `Date` instead of `string`
}
/// pet.ts
import { Animal } from './animal'
// remove the conflicting property from `Animal`, while concurrently extending the new `Pet` type to reintroduce `birthday` as a `Date`
type Pet = Omit<Animal, 'birthday'> & {
birthday: Date
ownerId: number
}
// the compiler accepts the extended definition of `Pet`
const pet: Pet = {
name: 'fido',
age: 2,
birthday: new Date(), // now a `Date`, not string!
ownerId: 1
}
Explanation
To simplify the example and make it more comprehensible, I've omitted the usage of declare module
. Consider the code snippet below:
/// animal.ts - good
export interface Animal {
name: string
age: number
}
export interface Animal {
birthday: string
}
The above code is completely permissible in TypeScript. The compiler merges both declarations of Animal
into a single definition.
Lets examine a different scenario.
/// animal.ts - bad
export interface Animal {
name: string
age: number
birthday: string
}
export interface Animal {
birthday: Date
}
The issue should be evident. Both declarations of Animal
include birthday
, but with different types. How can the compiler determine the correct type for birthday
? While it could assume, thankfully it raises an error instead:
typescript: Subsequent property declarations must have the same type. Property 'birthday' must be of type 'string', but here has type 'Date'.