Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Observer): observer interface now allows partial Observers #1282

Merged
merged 1 commit into from
Feb 2, 2016
Merged

fix(Observer): observer interface now allows partial Observers #1282

merged 1 commit into from
Feb 2, 2016

Conversation

benlesh
Copy link
Member

@benlesh benlesh commented Feb 2, 2016

  • caveat is that there is no way to require at least one method on Observer in TypeScript, at least that I can find

related #1260

@kwonoj
Copy link
Member

kwonoj commented Feb 2, 2016

Looks good to me for now. I'll track how typescript side changes / updates are going to followup further.

@kwonoj
Copy link
Member

kwonoj commented Feb 2, 2016

Seems with current Typescript it can be achieved via below, not looking elegant bit though..

type Observer<T> = NextObserver<T> | ErrorObserver | CompleteObserver | (NextObserver<T> & ErrorObserver & CompleteObserver) | (ErrorObserver & CompleteObserver) | (NextObserver<T> & ErrorObserver) | (NextObserver<T> & CompleteObserver);

(copy-pasted from issue).

@benlesh
Copy link
Member Author

benlesh commented Feb 2, 2016

I experimented for a while with different approaches and this was the best I could come up with for developer ergonomics.

I tried this also:

export interface NextObserver<T> {
  isUnsubscribed?: boolean;
  next: (value: T) => void;
}

export interface ErrorObserver {
  isUnsubscribed?: boolean;
  error: (err: any) => void;
}

export interface CompletionObserver {
  isUnsubscribed?: boolean;
  complete: () => void;
}

export declare type Observer<T> = NextObserver<T> | ErrorObserver | CompletionObserver;

But that resulted in ugly experiences on the consumer end, where trying to call next on the Observer gave you TypeScript errors because "next" doesn't exist on " NextObserver | ErrorObserver | CompletionObserver"

@benlesh
Copy link
Member Author

benlesh commented Feb 2, 2016

@kwonoj ... haha you typed that while I was adding additional comments. Yes, I did try that, but it ended up being ugly on the side of whatever consumes the observer. For example and error like: o.next does not exist on NextObserver<T> | ErrorObserver | CompleteObserver | (NextObserver<T> & ErrorObserver & CompleteObserver) | (ErrorObserver & CompleteObserver) | (NextObserver<T> & ErrorObserver) | (NextObserver<T> & CompleteObserver);

@kwonoj
Copy link
Member

kwonoj commented Feb 2, 2016

Yes, it'll be quite unfriendly from consumer perspective. For now I'd rather allow observer to be fully optional interfaces given that most cases caller wouldn't pass empty object ({}) in general. Course this is based on assumption there'll be better ergonomics support from typescript will be available. I hope microsoft/TypeScript#4889 can be answer.

@benlesh
Copy link
Member Author

benlesh commented Feb 2, 2016

@kwonoj ... I got a solid answer from the TypeScript folks and reimplemented my solution. Now there is a PartialObserver<T> type that matches any partial observer. I've also updated all appropriate locations in code that could have partial observers.

@kwonoj
Copy link
Member

kwonoj commented Feb 2, 2016

Saw update from issue and this looks much better :) Change looks good to me.

p.s: just curious, how does error output now when partial observer does not have some interfaces? (as compare to above)

@benlesh
Copy link
Member Author

benlesh commented Feb 2, 2016

@kwonoj if you try to pass an empty object, for example, to something that accepts PartialObserver<T>, it complains that {} does not match NextObserver<T> | ErrorObserver | CompletionObserver... likewise if there's too many additional methods: { next() {}, blah () {} }.

@kwonoj
Copy link
Member

kwonoj commented Feb 2, 2016

Thanks for clarification :)

if (nextOrObserver && typeof (<Observer<T>>nextOrObserver).next === 'function') {
return this.observe(<Observer<T>>nextOrObserver);
accept(nextOrObserver: PartialObserver<T> | ((value: T) => void), error?: (err: any) => void, complete?: () => void) {
if (nextOrObserver && typeof (<PartialObserver<T>>nextOrObserver).next === 'function') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, I think this guard will accepts IterableIterator<T> (from the code which have only a runtime dynamically type). In today's RxJS context, can a generator be a Observer<T>?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saneyuki ... not really... generators have next, throw and return methods. Very, very early versions of this library where implemented in that manner, but it was abandoned when the es-observable spec moved away from that.

…s with PartialObservable<T>

- Observer<T> is the "full" observer interface
- PartialObserver<T> is any object with at least one method of the Observer interface
- Updates subscribe signature and Notification signatures to use PartialObserver instead of Observer

Related #1260
@benlesh benlesh merged commit 7b6da90 into ReactiveX:master Feb 2, 2016
@benlesh benlesh deleted the observer-interface-fix branch February 2, 2016 18:57
@lock
Copy link

lock bot commented Jun 7, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants