Typescript: Suggestion for Strict interfaces

Created on 21 Dec 2015  路  5Comments  路  Source: microsoft/TypeScript

I encountered a behavior of interface implementations which at first I taught was strange. Consider the following interfaces

interface IEventArgs {}
interface IDispatchable {
    dispatch(type: string, args: IEventArgs): void;
}

Upon implementing this, I expected that typescript would force me to use a matching signature, but it accepts every signature which vaguely matches the implementation.

For example this will not raise an error

// expected
class A implements IDispatchable {
    dispatch(type: string, args: IEventArgs): void {}
}

// according to typescript this is valid as well
class B implements IDispatchable {
    dispatch(): number { return 1; }
}

If I think about it in terms of JavaScript it makes sense that it would accept B. Even though someone would give me N arguments, the function can just ignore them. Moreover even though a function returns a number we can still ignore them.

But from a OO design perspective this is strange (at least to me). The signature of B's method dispatch does not even come close to the expected signature.

Suggestion

Now this is a long shot, but maybe more people support this idea. What if we can mark a interface (or the interface method) as strict. Which would mean that it would only accept implementations with the exact same function signature.

For example

interface IEventArgs {}
strict interface IDispatchable {
    dispatch(type: string, args: IEventArgs): void;
}

// good
class A implements IDispatchable {
    dispatch(type: string, args: IEventArgs): void {}
}

// error
class B implements IDispatchable {
    dispatch(): number { return 1; }
}

Another less elegant solution would be a config flag.

I actually don't have an idea if this is within the operation scope of typescript, but sharing ideas is never a bad thing to do. And maybe the makes of typescript have considered this already and made a specific design decisions, in that case I am curious why.

By Design

Most helpful comment

I was shocked when a co-worker informed me of this today. I get that B is a valid substitue for IDispatchable; however, if I am using interfaces as contracts within my codebase, if the contract changes, I would like to be "aware" of it as my implementation may not be robust enough to handle the change. It would be nice if there was a compiler flag (or a interface definition keyword like "strict") available to enforce strict adherence to function signatures in interfaces.

All 5 comments

The signature of B's method dispatch does not even come close to the expected signature.

There's actually not that much variance allowed. You couldn't have a base dispatch returning string overridden by one returning number, nor dispatch(x: string) overridden by dispatch(x: boolean). In this case B has taken advantage of both aspects of variance.

But there's nothing _wrong_ with B's implementation of dispatch that isn't a plausible design choice by the class author. B is a true substitute for IDispatchable.

Moreover, it's not clear why the definer of IDispatchable gets to choose whether or not its implementors have exact signature matches. Why does it care? Why does anyone care? What bugs are prevented here?

If it is by design, than that is end of discussion. I just was curious if ther was a reason for it being as it is, which you gave me. I found it strange at first because this isn't allowed in languages like C# and java, where the call signature must match exactly. But as I said, reflecting on how javascript treats extra arguments and return values, it makes sense.

As an aside, I realized my rhetorical questions at the end there might not have sounded as rhetorical as they were, so apologies for that if it sounded pushy. Thanks!

No probs, I wanted to answer very strongly on them, but after rereading them I realist the actual questions and tone you tried to set. ps. that wikipedia article is a good read.
Thanks again!

I was shocked when a co-worker informed me of this today. I get that B is a valid substitue for IDispatchable; however, if I am using interfaces as contracts within my codebase, if the contract changes, I would like to be "aware" of it as my implementation may not be robust enough to handle the change. It would be nice if there was a compiler flag (or a interface definition keyword like "strict") available to enforce strict adherence to function signatures in interfaces.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartynasZilinskas picture MartynasZilinskas  路  3Comments

manekinekko picture manekinekko  路  3Comments

jbondc picture jbondc  路  3Comments

siddjain picture siddjain  路  3Comments

remojansen picture remojansen  路  3Comments