I have created a class in Typescript that implements a simple stream (FRP). Now I want to extend it with client side functionality (streams of events). To illustrate my problem, here is some pseudo-code:
class Stream<T> {
map<U>(f: (value: T) => U): Stream<U> {
// Creates a new Stream instance that maps the values.
}
// Quite a few other functions that return new instances.
}
This class can be used both on the server and on the client. For the client side, I created a class that extends this one:
class ClientStream<T> extends Stream<T> {
watch(events: string, selector: string): Stream<Event> {
// Creates a new ClientStream instance
}
}
Now the ClientStream
class knows about map
but the Stream
class doesn't know about watch
. To circumvent this, functions call a factory method.
protected create<U>(.....): Stream<U> {
return new Stream<U>(.....)
}
The ClientStream
class overrides this function to return ClientStream
instances. However, the compiler complains that ClientStream.map
returns a Stream
, not a ClientStream
. That can be 'solved' using a cast, but besides being ugly it prevents chaining.
I don't really like this pattern, but I have no other solution that is more elegant. Things I've thought about:
- Use composition (decorator). Not really an option given the number of methods I would have to proxy through. And I want to be able to add methods to
Stream
later without having to worry aboutClientStream
. - Mix
Stream
intoClientStream
. More or less the same problem,ClientStream
has to know the signatures of the functions that are going to be mixed in (or not? Please tell). - Merge these classes into one. This is a last resort, the
watch
function has no business being on the server.
Do you have a better (more elegant) solution? If you have an idea that gets closer to a more functional style, I'd be happy to hear about it. Thanks!
Aucun commentaire:
Enregistrer un commentaire