It would appear that the current way RxJS detects other observables is not working as expected, while other libraries can adapt from each other.
Current Behavior
The from function in RxJS 6.3.3 does not seem able to adapt xstream and most while the older RxJS 5 Observable.from was able to. The following error is reproduced in both cases:
TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
Both xstream and most provide Symbol polyfills:
Additional testing has confirmed:
webpack but it does in node, jest, and browserify.Reproduction
xstream to rxjs, does not work:const { from: observableFrom } = require('rxjs')
const { isInteropObservable } = require('rxjs/internal/util/isInteropObservable')
const { default: xs } = require('xstream')
const num$ = xs.from([ 1, 2, 3, 4 ])
console.log('Is num$ an observable?', isInteropObservable(num$)) // false
const adapt$ = observableFrom(num$) // error here
adapt$.subscribe(console.log)
xstream to rxjs, working after importing xstream first:const { default: xs } = require('xstream')
const { from: observableFrom } = require('rxjs')
const { isInteropObservable } = require('rxjs/internal/util/isInteropObservable')
const num$ = xs.from([ 1, 2, 3, 4 ])
console.log('Is num$ an observable?', isInteropObservable(num$)) // true
const adapt$ = observableFrom(num$)
adapt$.subscribe(console.log)
most, not working:const { from: observableFrom } = require('rxjs')
const { isInteropObservable } = require('rxjs/internal/util/isInteropObservable')
const most = require('most')
const num$ = most.from([ 1, 2, 3, 4 ])
console.log('Is num$ an observable?', isInteropObservable(num$)) // false
const adapt$ = observableFrom(num$) // error here
adapt$.subscribe(console.log)
rxjs to xstream either unless we import xstream first:const { from: observableFrom } = require('rxjs')
const { default: xs } = require('xstream')
const num$ = observableFrom([ 1, 2, 3, 4 ])
const adapt$ = xs.from(num$)
adapt$.addListener({
next: console.log
})
Expected behavior
The order of import should not matter, and the jest environment would work like webpack.
Environment
Possible Solution
rxjs/src/internal/symbol/observable.ts could be defined the same way the other libraries do it:Symbol('observable')
isInteropObservable could be patched to check for the same symbol xstream and most use?xstream or most could be included?Additional context/Screenshots
cyclejs project with rxjs.jest.setup.js seems to have fixed the issue for now:import xs from 'xstream' // eslint-disable-line
Thank you and sorry in advance if I've diagnosed the wrong source :bowing_man:
Need some digging, esp why our interop utility doesn't work based on import order.
couple of clarifications meanwhile
could be patched to check for the same symbol xstream and most use?
I think we already do, need to figure out why it doesn't work.
A similar polyfill to xstream or most could be included?
from v6, we intentionally removed polyfilling symbol for our own but only check if symbol exists.
Need some digging, esp why our interop utility doesn't work based on import order.
If RxJS loads and there is no Symbol.observable, the string '@@observable' is used instead.
If xstream loads and there is no Symbol.observable, it assigns Symbol('observable') to Symbol.observable. xstream only uses '@@observable' if Symbol does not exist.
Don't we revalidate existense of symbol each time time when fn called? I thought we did that.
Uh welp. :sweat_smile:
Any updates on this? I faced this issue with refract-rxjs which revalidates existence of symbol. It brought a hard to track bug that started to occur when I reordered my imports.
I'm experiencing this too, unable to convert xstream streams to rxjs streams.
Digging into this:
It looks like the issue is we're not using unique symbol types with our typings. Furthermore, everyone else is using symbol-observable, which we could probably use as well, after we update it to _also_ use unique symbol in it's types.
https://github.com/benlesh/symbol-observable/issues/41
In the end, I'm not sure what we should do here to fix the typings though. It seems like once something is imported from another module or otherwise stuffed in a variable, TypeScript gets rather confused about what works and what doesn't.
There is another issue in the original post here, which is that, really, polyfills should always be applied _before_ any libraries are loaded. So the runtime fix would be to just ensure the polyfilling happened first before the other imports.
The TypeScript issue I'm not sure we can fix at the moment.
I'm closing this for now, but I'm willing to reopen this later if this becomes a major issue.
This is related to issue #3890, and there's a solid workaround for the typings issue
The runtime issue can be resolved with a simple polyfill or just changing the order of imports.
// Running this code before any of your imports will resolve any runtime issues.
if (typeof Symbol === 'function') {
if (!Symbol.observable) {
Symbol.observable = Symbol('observable');
}
}