Reputation: 987
Why do neither my TS linter nor compiler complain about the type massacre in my test
method here? It appears that the item: T
constraint isn't validated at all.
Tested on TS 3.8.3 and an old 3.2.2:
export class Foo {}
export class Bar {}
export class FooBar {
test() {
const thisIsNotABar: Bar = this.echo<Bar>(new Foo());
}
echo<T>(item: T): T {
return item;
}
}
Upvotes: 0
Views: 35
Reputation: 327744
Ah, welcome to TypeScript's structural type system. In TypeScript, two types are the same if they have the same shape or structure. It does not depend on the name or declaration of the types, as in nominal type systems you might be more used to in other languages.
So, even though your Foo
and Bar
have different names and different declarations, they have the same shape and structure; namely that of an empty object type. And so, in TypeScript, Foo
and Bar
are exactly the same type.
If you want Foo
and Bar
to be considered distinct, you should add some incompatibility of structure, such as giving them different properties:
export class Foo {
foo = ""
}
export class Bar {
bar = ""
}
If you do that, the error you expected should happen:
const thisIsNotABar: Bar = this.echo<Bar>(new Foo()); // error!
// Foo is not assignable to Bar
Okay, hope that helps; good luck!
Upvotes: 2
Reputation: 1405
This is because Foo and Bar are compatible (their definitions are identical). Try adding a property to one that isn't in the other and TypeScript should give you an error:
export class Foo { a: any }
export class Bar { b: any }
export class FooBar {
test() {
const thisIsNotABar: Bar = this.echo<Bar>(new Foo());
}
echo<T>(item: T): T {
return item;
}
}
Gives the error:
Argument of type 'Foo' is not assignable to parameter of type 'Bar'. Property 'b' is missing in type 'Foo' but required in type 'Bar'.
Upvotes: 2