Rxjs: `observableOf` and `observableFrom` instead of `of` and `from`

Created on 2 Apr 2018  路  10Comments  路  Source: ReactiveX/rxjs

Issues

  • People have strong feelings
  • IDEs like to color of in error
  • People that aren't used to RxJS don't know what of(1, 2, 3) means

Proposal

Rename of and from to observableOf and observableFrom.

Pros

  • It's less ambiguous and more explicit what code is doing
  • IDEs are happier about it
  • can make the change gradually without breaking everyone with an alias and a deprecation

Cons

  • It's WAY more verbose and makes code a bit more annoying to read.
  • It's another change to the library.
  • Most people using RxJS a lot in their apps know what of and from mean

Other thoughts

  • People can already to this with import aliases. `import { of as observableOf } from 'rxjs'; and the five extra characters there probably isn't going to kill them.
  • It might actually encourage the use of Arrays as return values (which is totally fine) inside of mergeMap et al: source$.pipe(mergeMap(() => of(1, 2, 3))) is the same as source$.pipe(mergeMap(() => [1, 2, 3])). The readability of this versus of is debatable.
  • observableFrom is probably the more annoying of the two changes, as it would be used more often to convert a promise ahead of other operators inside of flattening operators.
discussion

Most helpful comment

@Airblader to take the guessing out of the equation here are the results:

import { Component, Input } from '@angular/core';
import * as observable from 'rxjs';
import {take} from 'rxjs/operators';

@Component({
  selector: 'hello',
  template: `<h1>Inteval at {{interval | async}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  interval = observable.interval(1000).pipe(take(10));
}

Before I added the take operator and interval here how it looked after
ng build --prod --build-optimizer --source-map --eval-source-map

screen shot 2018-05-09 at 12 28 39 pm

There are some operators, but those are using by Angular itself.

Here is after I added interval to the above mentioned Component:

interval

As you can see even though import * as observable from 'rxjs'; was used only interval appeared in the optimized code.

I think this should resolve it.

All 10 comments

I'm indifferent with this one, but if we'are going to rename of, I'd vote to go for just instead - which most of Rx bindings (including .net's) are using but RxJS is a different one for those interface. It'll allow alignment between other bindings, instead of making name verbose like observableOf.

On our project, we already rename all such imports, e.g import { of as observableOf } from ....

The following works without any drawbacks:

import * as observable from 'rxjs';

observable.of(foo)

@alex-okrushko Importing like that will prevent tree-shaking, AFAIK. Also it requires you to prefix everything, not just the two functions in question.

@Airblader to take the guessing out of the equation here are the results:

import { Component, Input } from '@angular/core';
import * as observable from 'rxjs';
import {take} from 'rxjs/operators';

@Component({
  selector: 'hello',
  template: `<h1>Inteval at {{interval | async}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  interval = observable.interval(1000).pipe(take(10));
}

Before I added the take operator and interval here how it looked after
ng build --prod --build-optimizer --source-map --eval-source-map

screen shot 2018-05-09 at 12 28 39 pm

There are some operators, but those are using by Angular itself.

Here is after I added interval to the above mentioned Component:

interval

As you can see even though import * as observable from 'rxjs'; was used only interval appeared in the optimized code.

I think this should resolve it.

I think this should resolve it.

Certainly, thanks :-) I do have more questions about it, but that's a bit off topic here. I'll research it on my own.

@alex-okrushko That's an interesting result. I was also under the same impression as @Airblader that doing import *... would prevent tree shaking.

I now see that Ben mentioned that this is possible in another issue.

My understanding is that modern tree shakers will pick this up.

I might start doing that myself now that I know it's OK. For those new to RxJS, like me, it's helpful being able to do rx. and have the IDE provide the functions in that module. I'll maybe do the same with operators, although it's a bit more onerous to have to prefix everything.

Seems like doing import * as rx from "rxjs" or some such would be a workaround for those having issues with of and from.

As to the names of and from being unclear about what they do, if you rename of and from don't you also have to rename things like fromEvent and the other functions that create Observables? This goes similarly for operators.

If you decide to rename of and from because of naming collisions with TypeScript keywords, please also consider doing the same with never, which you mentioned in this issue.

@r3h0. NEVER is a constant now, differing from TypeScript never in case.

I am personally in favor of not removing operators (unless there is a collision), so I wouldn't want the rename. Doing import * as rx or import { of as rxOf } and the like are simple and acceptable alternatives that will keep the existing library more backwards compatible.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

peterbakonyi05 picture peterbakonyi05  路  4Comments

shenlin192 picture shenlin192  路  3Comments

cartant picture cartant  路  3Comments

marcusradell picture marcusradell  路  4Comments

unao picture unao  路  4Comments