0

I'll try to explain my situation with an example.

Say I have the interface:

interface EventListener<TArgs> {
    listen: () => TArgs
}

The implementation:

class Foo implements EventListener<UserConnectedArgs>, EventListener<UserDisconnectedArgs> {
    listen = (): UserConnectedArgs => {
        // user connection detection logic
    }
    listen = (): UserDisconnectedArgs => {
        // user disconnection detection logic
    }
}

And the usage:

const userConnectionListener: EventListener<UserConnectedArgs> = new Foo()
const userDisconnectionListener: EventListener<UserDisconnectedArgs> = new Foo()

I would get a "Duplicate identifier 'listen'" error.

Correct me if I'm wrong, but I believe (generally speaking) a class should be able to implement the same generic interface multiple times with different types, as it can implement a different behavior for each type argument.

Implementing the same concept in C# seems to work the way I intended it to work, but I am aware C# is more "type aware" during run-time than Typescript (or JavaScript for that matter) is.

And so I ask, how do you think I should go about this?

Thanks in advance!

JayLeeman
  • 1
  • 1
  • Like this? interface MyEventListener extends EventListener { listen: () => TArgs } – ZiiMakc Jan 08 '20 at 11:59
  • No, the above is not possible because there're no "real" overloads in typescript and there's no way to check generic type parameter at runtime and differentiate between overloads. Types do not exist at runtime. You'll need to provide some runtime value (e.g. parameter) to be able to "branch" implementation according to it – Aleksey L. Jan 08 '20 at 12:35
  • if `UserConnectedArgs` and `UserDisconnectedArgs` are classes you can also arrange something with `new Foo(UserConnectedArgs)`. Let me know if you need an example – Aleksey L. Jan 08 '20 at 13:03
  • https://stackoverflow.com/a/13212871/4420812 you can overload methods but implementation can be only one. – Maciej Sikora Jan 08 '20 at 14:00
  • You can't define two methods with same name in a class. Maybe you should create two classes and both implements the interface. – netdjw Jan 08 '20 at 15:52
  • I see, thank you all for the clarifications! – JayLeeman Jan 08 '20 at 18:27

1 Answers1

0

I'm new to generics in typescript, so maybe this is wrong... But to me it seems you don't need two different generic definitions:

interface EventListener<Args> {
    listen: () => Args
}

Class that uses different types of args

class Foo implements EventListener<Args> {
    listen() : Args {
        // the returned "something" value will have type Args
        return something
    }
}

Usage

const userConnectionListener: EventListener<UserConnectedArgs> = new Foo()
const userDisconnectionListener: EventListener<UserDisconnectedArgs> = new Foo()


userConnectionListener.listen()      // will return data of type UserConnectedArgs
userDisconnectionListener.listen()   // will return data of type UserDisconnectedArgs
Kokodoko
  • 26,167
  • 33
  • 120
  • 197
  • First of all, thanks for the response! Although, your solution means Foo has to be aware of each type Args can be, and implement a different logic for each. Instead of, knowing Args can be either UserConnectedArgs or UserDisconnectedArgs and support only the detection of those two (because those are the ones you chose to implement). – JayLeeman Jan 08 '20 at 12:18
  • Yes, you may need an `if` statement in `Foo` to check what type of arguments you are dealing with, you don't want that? – Kokodoko Jan 08 '20 at 12:23
  • Yes, if-statements/switch-cases are something I am trying to avoid, with the purpose of letting a run-time type system (like in C#) do the "type-to-method-routing" for me. I understand Typescript is lacking such a thing, so I am trying to find a solution that avoids breaking the Open-Closed principle as much as I can. – JayLeeman Jan 08 '20 at 12:49