Skip to content

RFC: A new way of "piping" #7203

Open
Open
@benlesh

Description

@benlesh

Given the move away from lift: #7201 #7202

We can make our observable even more compatible with other observables by migrating us away from the pipe method. This is not something that would happen immediately, rather over a very, very long period. The idea is to increase compatibility and improve ergonomics.

Problem: It's annoying to have to from(x) types in order to use our operators with them

There's a common issue where people want to convert other things to observables in order to use our operators. Whether it's an array or a promise, there are times were you need to do from and the only reason you're doing it is because you want that .pipe method, and you want an observable to operate on.

Problem: pipe is a method

  1. It's not tree shakable
  2. It's unlikely to exist on "other observables".

The second one is more of a problem, honestly. If people implement code with the expectation that pipe exists as a method on whatever observable they get, then even while we've made sure our operators will work with any "same-shaped" observable, that custom code will break, because it's expecting pipe to be a method.

Proposal

A new rx method that accepts an ObservableInput as the first argument, and a rest of operators:

export function rx<A, B>(source: ObservableInput<A>, a: OperatorFunction<A, B>): Observable<B>;
export function rx<A, B, C>(source: ObservableInput<A>, a: OperatorFunction<A, B>, b: OperatorFunction<B, C>): Observable<C>;
export function rx<A, B, C, D>(source: ObservableInput<A>, a: OperatorFunction<A, B>, b: OperatorFunction<B, C>, c: OperatorFunction<C, D>): Observable<D>;
// ... and so on
export function rx<T>(source: ObservableInput<T>, ...operators: OperatorFunction<T, any>[]): Observable<unknown> {
  returm pipeArray(operators)(from(source))
}

(Technically, rx is just a standard functional pipe with some specific types, it could be the same pipe method we expose under the hood)

The usage would be as such:

import { rx, map, delay } from 'rxjs'


rx(source$, map(n => n + n)).subscribe(console.log)

// or

rx(somePromise, delay(1000)).subscribe(console.log)

// or

rx(someAsyncIterable, map(n => n + n)).subscribe(console.log)

// ...and so on.

Bonus? from could migrate to just be rx as well

For a long time people have complained about from being a horrible name for an exported function. (Although I do like import { from } from './from' in our codebase 😄). This would mean that couple could technically just do: rx(somePromise) and it's the same as from(somePromise).

Metadata

Metadata

Assignees

No one assigned

    Labels

    8.xIssues and PRs for version 8.x9.xAGENDA ITEMFlagged for discussion at core team meetings

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions