JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing

Someone asked me some time ago to share my thoughts on Async/Await in JavaScript. It is my belief that Async/Await (and to some extent*, Optional Chaining Syntax) is a missed opportunity in the evolution of the language.

Consider the following three p…


This content originally appeared on DEV Community and was authored by Aldwin Vlasblom

Someone asked me some time ago to share my thoughts on Async/Await in JavaScript. It is my belief that Async/Await (and to some extent*, Optional Chaining Syntax) is a missed opportunity in the evolution of the language.

Consider the following three programs:

const f = () => foo .? bar .? baz;
const nullableResult = f();
const f = async () => { return await (await (await foo).bar).baz }
const thennableResult = f();
const f = () => foo.flatMap(({bar}) => bar.flatMap(({baz}) => baz));
const manyResults = f();
  • In the first program, we assume that foo is a Nullable object with a bar property, that's a Nullable object with a baz property, that's a Nullable value.
  • In the second, we assume that foo is a Thenable (also known as Promise) of an object with a bar property, that's a Thenable of an object with a baz property, that's a Thenable of a value.
  • In the third, we assume that foo is a "Manyable" (also known as Array) of objects with bar properties, that are Manyables of objects with baz properties, that are Manyables of values.

I'm sure you can already see the pattern here. But what if I told you that JavaScript could have evolved so that these three programs would be exactly the same, and work polymorphically on inputs of type Nullable<T>*, Thenable<T>, and Manyable<T>?

type Nullable<T> = T | null;
type Thenable<T> = Promise<T>;
type Manyable<T> = T[];

All that would be needed for that, is a common interface (like the Promise .then function) that the language syntax could build on (like they did with Async/Await). In fact, valid implementations of that potential interface already exist. It's just flatMap. We can also implement flatMap for Thenable and for Nullable:

const Nullable = {
  flatMap(nullable, next){
    return nullable === null ? null : next(nullable);
  }
}

const Thenable = {
  flatMap(thenable, next){
    return thenable.then(value => next(value));
  }
}

const Manyable = {
  flatMap(manyable, next){
    return manyable.flatMap(value => next(value));
  }
}

So we have our three flatMaps that have exactly the same interface. At this point, we're already able to create a function like the f we started with, but polymorphic (working on "anythingable" with a flatMap):

const f = (Somethingable) => (
  Somethingable.flatMap(foo, ({bar}) => (
    Somethingable.flatMap(bar, ({baz}) => baz)
  ))
);

ℹ️ Try it out with nullableResult = f(Nullable)

If we'd associate these functions with the right prototypes, then we wouldn't even need to pass the correct interface implementation:

Promise.prototype.flatMap = function(next){
  return Thenable.flatMap(this, next);
}
// f now works on Arrays, and on Promises:
const f = () => foo.flatMap(({bar}) => bar.flatMap(({baz}) => baz));

To some extent*, JavaScript could have adopted this approach, and given us a single syntax for flatMap that would be able to work with anything that's flat-mappable:

> const foo = Promise.resolve({
  bar: Promise.resolve({ baz: Promise.resolve("hello") })
});

> foo ?. bar ?. baz
Promise<"hello">
> const foo = [{ bar: [{ baz: ["hello"] }] }];

> foo ?. bar ?. baz
[ "hello" ]

Or, like a more async-awaitey one:

const f = flattening () => {
  const a = flatten foo;
  const b = flatten a.bar;
  return flatten b.baz;
}

Take a moment to let that sink in. This version of Async/Await looks exactly the same, but works on anything that's flattenable, not just Promises. It could have even integrated with custom types that have flatMap functions, like Observables, Iterables, Tasks, and whatnot. Instead, we're slowly getting a new special syntax for every new flatmappable type that's introduced to the language, in a process that's unfolding over the course of years, if not decades 😞

(This was one of the purposes of the Fantasy Land specification, to define common interfaces for generalized operations that could benefit from language-syntax-support.)

* The extent to which this is possible with Nullable is very limited, due to the nature of Nullable values. While Arrays and Promises are explicit wrappers around a value, any value can potentially be null implicitly, so you wouldn't know what to do when flat-mapping over a Nullable Promise, for example. To get around this, modern languages have a Nullable type (typically called Option) that wraps a value, as opposed to living alongside it.

This somewhat validates the existence of Optional Chaining syntax, although I would've preferred seeing a flatMap syntax (and an Option type), over a commitment to the problematic Nullable type through the succinct Optional Chaining syntax.


This content originally appeared on DEV Community and was authored by Aldwin Vlasblom


Print Share Comment Cite Upload Translate Updates
APA

Aldwin Vlasblom | Sciencx (2025-02-19T12:12:03+00:00) JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing. Retrieved from https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/

MLA
" » JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing." Aldwin Vlasblom | Sciencx - Wednesday February 19, 2025, https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/
HARVARD
Aldwin Vlasblom | Sciencx Wednesday February 19, 2025 » JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing., viewed ,<https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/>
VANCOUVER
Aldwin Vlasblom | Sciencx - » JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/
CHICAGO
" » JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing." Aldwin Vlasblom | Sciencx - Accessed . https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/
IEEE
" » JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing." Aldwin Vlasblom | Sciencx [Online]. Available: https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/. [Accessed: ]
rf:citation
» JavaScript’s Missed Opportunity: Async/Await, Optional Chaining, and flatMap are the same thing | Aldwin Vlasblom | Sciencx | https://www.scien.cx/2025/02/19/javascripts-missed-opportunity-async-await-optional-chaining-and-flatmap-are-the-same-thing/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.