Skip to content

Commit 0ab91eb

Browse files
authored
fix(subscribe): allow interop with Monio and other libraries that patch function bind
* fix(subscribe): allows functions where bind has been patched to be weird Apparently, code exists in the wild that will patch function bind to do something other than return a function that will execute the function instance, so we cannot rely on bind. Resolves #6783 * refactor: Alternative bind approach * chore: update side-effects golden files. * chore: Add comment about why bind is captured * chore: update side-effect files again
1 parent e43063a commit 0ab91eb

File tree

14 files changed

+64
-5
lines changed

14 files changed

+64
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1+
const _bind = Function.prototype.bind;
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
import "tslib";
2+
3+
const _bind = Function.prototype.bind;

integration/side-effects/snapshots/esm/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
const _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {

integration/side-effects/snapshots/esm/operators.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
const _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {

integration/side-effects/snapshots/esm/testing.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
const _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1+
const _bind = Function.prototype.bind;
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
import "tslib";
2+
3+
var _bind = Function.prototype.bind;
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
import "tslib";
2+
3+
var _bind = Function.prototype.bind;

integration/side-effects/snapshots/esm5/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
var _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {

integration/side-effects/snapshots/esm5/operators.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
var _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {

integration/side-effects/snapshots/esm5/testing.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import "tslib";
22

3+
var _bind = Function.prototype.bind;
4+
35
var NotificationKind;
46

57
(function(NotificationKind) {
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
import "tslib";
2+
3+
var _bind = Function.prototype.bind;

spec/Observable-spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,34 @@ describe('Observable', () => {
191191
});
192192

193193
describe('subscribe', () => {
194+
it('should work with handlers with hacked bind methods', () => {
195+
const source = of('Hi');
196+
const results: any[] = [];
197+
const next = function (value: string) {
198+
results.push(value);
199+
}
200+
next.bind = () => { /* lol */};
201+
202+
const complete = function () {
203+
results.push('done');
204+
}
205+
complete.bind = () => { /* lol */};
206+
207+
source.subscribe({ next, complete });
208+
expect(results).to.deep.equal(['Hi', 'done']);
209+
});
210+
211+
it('should work with handlers with hacked bind methods, in the error case', () => {
212+
const source = throwError(() => 'an error');
213+
const results: any[] = [];
214+
const error = function (value: string) {
215+
results.push(value);
216+
}
217+
218+
source.subscribe({ error });
219+
expect(results).to.deep.equal(['an error']);
220+
});
221+
194222
it('should be synchronous', () => {
195223
let subscribed = false;
196224
let nexted: string;

src/internal/Subscriber.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ export class Subscriber<T> extends Subscription implements Observer<T> {
136136
}
137137
}
138138

139+
/**
140+
* This bind is captured here because we want to be able to have
141+
* compatibility with monoid libraries that tend to use a method named
142+
* `bind`. In particular, a library called Monio requires this.
143+
*/
144+
const _bind = Function.prototype.bind;
145+
146+
function bind<Fn extends (...args: any[]) => any>(fn: Fn, thisArg: any): Fn {
147+
return _bind.call(fn, thisArg);
148+
}
149+
139150
export class SafeSubscriber<T> extends Subscriber<T> {
140151
constructor(
141152
observerOrNext?: Partial<Observer<T>> | ((value: T) => void) | null,
@@ -166,9 +177,9 @@ export class SafeSubscriber<T> extends Subscriber<T> {
166177
} else {
167178
context = observerOrNext;
168179
}
169-
next = next?.bind(context);
170-
error = error?.bind(context);
171-
complete = complete?.bind(context);
180+
next = next && bind(next, context);
181+
error = error && bind(error, context);
182+
complete = complete && bind(complete, context);
172183
}
173184

174185
// Once we set the destination, the superclass `Subscriber` will

0 commit comments

Comments
 (0)