The root problem lies in the fact that One
and Two
have been defined as mutually compatible types.
Although there may not be a definitive source of documentation for this particular issue, referencing the (slightly outdated) TypeScript specification reveals that if all properties of a target object type T align with those of a source type S, then a value of type S can be assigned to a variable of type T.
In this scenario, One
is assignably equivalent to Two
due to:
Two
's optional property common
is a string
, just like One
's;
Two
's optional property two
is a string
, while One
lacks a property by that name.
Conversely, Two
can be assigned to One
for similar reasons:
One
's optional property common
matches Two
's;
One
's optional property one
corresponds to Two
's, although Two
does not possess a property named this way.
This compatibility might appear unexpected. However, TypeScript 2.4 introduced weak type detection that mandates at least one common property between all-optional-property types like One
and Two
. Yet, since both include the common
property, weak type checking is disabled.
To differentiate between two inadvertently compatible types, consider adding problematic property keys explicitly to the opposite types as optional properties of type never
or undefined
:
export interface One {
common?: string
one?: string;
two?: undefined;
}
export interface Two {
common?: string
one?: undefined;
two?: string;
}
This adjustment doesn't alter the intended assignments to these types:
const one: One = {
common: 'common',
one: 'One'
}; // remains valid
const two: Two = {
common: 'common',
two: 'Two'
} // still acceptable
However, now the compiler treats One
and Two
as separate entities:
func(one); // generates an error!
// ~~~ <-- Properties' types are incompatible.
Hopefully, this advice proves beneficial. Best of luck!
Link to Playground for Code Testing