Can't extend the same interface with different type parameters #11700
Labels
Needs Proposal
This issue needs a plan that clarifies the finer details of how it could be implemented.
Suggestion
An idea for TypeScript
This might sound like obviously correct behaviour. There's a very strong use case in the Node.js type definitions alone though, and I think type aliases show an avenue for this that could become a manageable workaround that's accessible without too much work.
Motivation
In the Node type definitions, we have a huge amount of duplication for EventEmitter types, which could be removed if we could write something like this:
Currently in the Node type definitions we implement EventEmitters like the above by duplicating every one of the EventEmitter methods for every single event that an object can have. That results in a huge amount of code in lots of places. These interfaces don't even bother typing all the methods they could (e.g. removeListener, listenerCount, listeners) presumably because that would make this even worse.
This would all be drastically simplified and made much more maintainable if something like the above was possible.
Type alias approach
In a perfect world, it would be wonderful if this Just Worked, and the above code defined method overrides for each of the combinations where they conflicted, more or less equivalent to the currently manually maintained net.Server definition.
I've seen other explanations of why this won't work with interfaces directly though. Unfortunately the suggested workaround for this problem generally is to manually merge the method declarations, which would defeat the point here.
You can get closer with type aliases:
This isn't a fully equivalent alternative though; critically you can't extend this type with another interface, or extend from the intersection expression itself (
TS2312: An interface may only extend a class or another interface
/TS2499: An interface can only extend an identifier/qualified-name with optional type arguments
).Options
There's a few things TypeScript could do that would solve this:
A & B
) in interfacesI haven't dug into this in depth, but either 2 or 3 sound like they would work around the issues with 1 (as the rules for merging are well defined), and would provide relatively clean solutions to solving these problems generally.
The text was updated successfully, but these errors were encountered: