0

In Typescript, I have encountered the following curiosity when passing a variable of one interface type to a function that expect a parameter of a different interface type.

Lets declare two interfaces, one for a Fruit and one for a Car:

interface Fruit { name: string }
interface Car   { name: string, wheels: number }

Now, let's declare a method that should do something with a Fruit only:

function fruitOnly( paramFruit: Fruit ): void {
    console.log( paramFruit.name + " is a fruit!" );
}

Finally, let's test it out:

let car: Car = { name: "Carrie the Car", wheels: 4 };
fruitOnly( car );

Result:

Carrie the Car is a fruit!

Question: Why do I not get a warning about car not being of type Fruit? (when trying to pass it as a parameter to fruitOnly( paramFruit: Fruit )?

I was under the impression, the point of TypeScript was to help me not pass parameters of the wrong types? I'm assuming the reason for this is that both interfaces happen to have the name property. Is there a workaround for this, or is this expected behaviour?

Desired behaviour: I would like to get a warning that I am passing the wrong type to the function.

Ben
  • 15,938
  • 19
  • 92
  • 138
  • 2
    TypeScript is *structurally*, not *nominally*, typed. Really what you're saying is that `fruitOnly` must take things that have a `string`-type property called `name` - from the perspective of the content of the method, that's all that matters anyway. If you actually need to differentiate, see e.g. http://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types. Note that the error you get for a type without that property is `Argument of type 'Foo' is not assignable to parameter of type 'Fruit'` - not assignable to, rather than not named. – jonrsharpe Apr 27 '18 at 11:44
  • See also e.g. https://stackoverflow.com/q/26810574/3001761 and the issue on the TS GitHub https://github.com/Microsoft/TypeScript/issues/202 – jonrsharpe Apr 27 '18 at 11:49
  • your interfaces are the same in terms of their structure (only one property: `name`). try defining `Car` with property `Name` instead of `name`. – dee zg Apr 27 '18 at 11:56
  • i see @jonrsharpe was quicker :) – dee zg Apr 27 '18 at 11:57
  • Removed the https://stackoverflow.com/questions/49260143/how-do-you-emulate-nominal-typing-in-typescript duplicate, the other one is more relevant imo – Titian Cernicova-Dragomir Apr 27 '18 at 11:59
  • Ok, I can see how both variables *look* the "same", if both interfaces only have the `name` property. However, I now have added a `wheels` property to the `Car` interface. And still, I can happily pass a `Car` with a `name` and `wheels` to a function that should expect a `Fruit` with a `name` only. So in the function, I now have a (name, wheels) where I expect a (name). Surely that can't be right? – Ben Apr 27 '18 at 12:04
  • But the function doesn't use `.wheels` (it couldn't, that *would* be a compiler error as not all things with `.name` have `.wheels`). It doesn't care that there are other properties it isn't using, just that all of the ones it does use exist. – jonrsharpe Apr 27 '18 at 12:13

0 Answers0