TL;TR

TypeScript is based on duck typing: even if you build a nested tree of types it will try to match them based on raw properties rather than variance.

The domain

Let’s define two interfaces like:

Then define an interface for a class which will have a method to return an array of Equipment

Let’s now say we have a function (could be a generic service) returning a list of Employee

and finally go and implement our class:

The problem

What’s happening? We have two unrelated types and we are allowed to pass Employee instead of Equipment.
This kind of mistake will not be detected by the compiler for a very simple reason: it is not a mistake to him.

Since TypeScript uses Duck Typing to match interfaces it just looks up for the required properties, and an Employee can also be an Equipment for the simple fact that it has the id property.
To prove this behaviour, try to add another method and invert the cast:

This time the error is thrown because the compiler looks up for id, then name and can’t find it.

The bottom line

Due to TypeScript’s nature, the static type check is not enough to catch misuse of unrelated types.

Using name-spaced keys for you interfaces can help but it drives to cluttered and redundant declarations like Employee.employeeName  which is pretty ugly.

Another suggestion is to be as much specific as possible about interface’s properties, but as soon as you will add optional properties it will become again weak.

Just take the annotation as they are, a mere developer’s wish, and enforce among your team testing, runtime assertion and code reviews.