# Promise chaining operator

**URL:** <https://es.discourse.group/t/promise-chaining-operator/1747>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [June 28, 2023, 7:36am UTC](https://es.discourse.group/t/promise-chaining-operator/1747 "2023-06-28T07:36:08Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lehks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/lehks/32/1790_2.png) [@Lehks](https://es.discourse.group/u/Lehks)\
**Post date:** [June 28, 2023, 7:36am UTC](https://es.discourse.group/t/promise-chaining-operator/1747/1 "2023-06-28T07:36:08Z")

</div>

# Current Situation / Problem

Promises have been a great feature to allow for asynchronous operations while avoiding callback hell by allowing chaining through `.then()`. After that, `async`/`await` have been introduced to once again make code more readable by making it so that asynchronous code looks pretty much like regular code (plus the `await` operator, of course).

However, one area that neither `.then()` nor `await` solve to an acceptable degree is property access chaining. Suppose we have synchronous code like this:

```javascript
one().two().three()

```

This looks very nice and is well readable. It does however not work if these functions are asynchronous and return a Promise. In that case, chaining would look like one of the following lines:

```javascript
one().then(result => result.two()).then(result => result.three())
// or
(await (await one()).two()).three()

```

Both of these solutions are less than ideal. The first solution is more than three times longer because of all the `.then()` calls. The second solution is shorter (although still longer then synchronous chaining), but uses a lot of nesting (the leftmost `await` belongs to the call of `.two()`).

The nesting can be somewhat circumvented by using the proposed pipeline operator, but this is also not the shortest or most readable solution:

```javascript
await one() |> await %.two() |> %.three()

```

The more practical solution is to simply put every asynchronous call on a single line, but this requires a separate single-use variable and a lot of vertical space:

```javascript
const oneResult = await one();
const twoResult = await oneResult.two();
twoResult.three();

```

# Proposal

## Basic Concept

To solve this problem, I would propose a new operator (`->` will be used as a placeholder for this operator for now). This operator does two things. It awaits the Promise and then serves as property access (dot operator). This operator would allow the functions from above to be chained like this:

```javascript
one()->two()->three()

```

And would be functionally equivalent to this example from above:

```javascript
one().then(result => result.two()).then(result => result.three())
// or
(await (await one()).two()).three()

```

Such an operator would be very convenient in cases where data is fetched asynchronously (e.g. from a web server or a database) and then further processed (e.g. using array `.map()`). For example, fetching to-dos and making their titles uppercase would look like this:

```javascript
fetch('https://jsonplaceholder.typicode.com/todos')->json()->map(todo => ({ ...todo, title: todo.title.toUpperCase() }))

```

## Arrow Rationale

Using an arrow as the operator (`->`) was inspired by C++ which uses the same operator for dereferencing and property access (which is comparable to this use case of awaiting and property access). It also very nicely denotes the order in which the properties are being accessed.

## Optional Chaining & String Property Access

The operator would also support optional chaining and string property access:

```javascript
// optional chaining
one()?->two()

// string property access
one()->['two']

```

## Usage with non-Thennable values

An open question would be how the operator behaves in cases where the object that it is called on is not Thennable, e.g. `'Hello World'->toString()`. So far, I see can see two options:

1. The call fails (just like calling `.then()` on a non-Thennable object would fail). This has the disadvantage that it makes values with the type `T | Promise<T>` difficult to use because it is not known whether the operator will fail or not. This would also make the operator easier to implement by transpilers such as Babel or TypeScript, because they soley need to replace the `->` operator with the respective `.then()` call.
2. The value will be wrapped into a promise if it is not Thennable (similarly to an `async` function does when a non-Promise is returned, or `await` does when awaiting a non-Promise value). This makes the operator easier to use, but I do not know whether this has any runtime implications in regard to performance. This option seems to be more convenient and should be preferred if it does not kill performance.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [June 28, 2023, 12:11pm UTC](https://es.discourse.group/t/promise-chaining-operator/1747/2 "2023-06-28T12:11:55Z")

</div>

[https://github.com/tc39/proposal-eventual-send](https://github.com/tc39/proposal-eventual-send)

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [June 28, 2023, 6:03pm UTC](https://es.discourse.group/t/promise-chaining-operator/1747/3 "2023-06-28T18:03:22Z")

</div>

Additionally, please see previous discussions on this topic:

> [@Async property accessor: -\>](https://es.discourse.group/t/async-property-accessor/765):
>
> The idea is to access a property of an awaited value to allow deep chaining of async operations. Right now, to accomplish that kind of chaining you need to write: const baz = await (await (await fetchFoo()).fetchBar()).fetchBaz(); That can get pretty awkward pretty fast. My idea is a new operator that accomplishes this without all the nested parens: const baz = await fetchFoo()-\>fetchBar()-\>fetchBaz(); Additionally, they can be optionally chained like the other property accessors: const ba…

> [@bang await chaining operator](https://es.discourse.group/t/bang-await-chaining-operator/940):
>
> // this is verbose const response = await fetch('/posts') const posts = await response.json() // chaining multiple await expressions in one line is awkward const posts = await (await fetch('/posts')).json() // proposal: chain together multiple awaits with !. const posts = await fetch('/posts')!.json()

> [@The "future-seeing-arrow" proposal.](https://es.discourse.group/t/the-future-seeing-arrow-proposal/1626):
>
> The idea is to provide a new -\> "operator", that conceptually serves a similar purpose as a "." in a fluent-API, however, it's given a special super-power. The initial function in the chain will be allowed to see everything that happens in the chain of -\>, and is in charge of executing everything in the chain. In reality, the -\> syntax is just a simple syntax sugar that decomposes into an array of tuples. Here's an example. // With the `-\>` operator let data = beginAnimation({ duration: '10ms'…
