Reputation: 10703
Object types are compared structurally. For example, in the code fragment below, class 'CPoint' matches interface 'Point' because 'CPoint' has all of the required members of 'Point'. A class may optionally declare that it implements an interface, so that the compiler will check the declaration for structural compatibility. The example also illustrates that an object type can match the type inferred from an object literal, as long as the object literal supplies all of the required members.
interface Point {
x: number;
y: number; }
function getX(p: Point) {
return p.x; }
class CPoint {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
} }
getX(new CPoint(0, 0)); // Ok, fields match
getX({ x: 0, y: 0, color: "red" }); // Extra fields Ok
getX({ x: 0 }); // Error: supplied parameter does not match
In their example CPoint
is considered of type Point
, since it is of type Point
I can pass it anywhere I can a Point
. If Point
stated that all implementors had method Foo(x:string)
, CPoint
wouldn't have that method. Thus anyone accepting a Point
and expecting to use Foo
would blow up if CPoint
was passed into it.
My question is, am I interpreting this wrong, if not why is this considered a good enough to put into the language specs?
Upvotes: 0
Views: 571
Reputation: 12250
The type definitions/interfaces one creates are just a compile-time thing and in my opinion, the structural subtyping is a great feature.
If you extend the Point
interface with an additional method Foo(x: string)
, you tell the compiler that every object that wants to be a Point
now also needs this method. In my opinion, this is exactly what you want to have because you can spot all places where you are passing objects that are lacking these additional properties.
Before adding such a method to an interface, it's probably better to ask yourself, if every object that has the characteristics of a Point
really needs this method. In my experience it is often better to introduce some more interfaces, e.g. Fooable
and using this where you need an object that needs to have the Foo
method.
If you have a method that really needs objects having both characteristics, (x,y) and Foo, you can do something like this:
function myMethodRequiringASpecialObject(x: Point & Fooable) {}
This is called "intersection types". See more here: https://basarat.gitbooks.io/typescript/content/docs/types/type-system.html
Upvotes: 1
Reputation: 220964
If Point stated that all implementors had method Foo(x:string), CPoint wouldn't have that method. Thus anyone accepting a Point and expecting to use Foo would blow up if CPoint was passed into it.
If you did this, you would get a compile-time error that CPoint
lacked the Foo
method. I recommend trying it on the TypeScript Playground.
Upvotes: 2