This is actually pretty funny. I coded javascript for a solid ~18 years (I stopped about 3 years ago) and the majority of the concerns in this list are from the past 10 years. What I find glaringly absent, which would have been present if this were written in 2013, is the absence of polyfills.

What other things that were JS nightmares in 2013 have largely ceased to exist? (Only to be replaced by this funny list.)

This is my favorite part: "You stop to count how many tools and parsers work on your codebase: TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser. You are not sure if you missed any. You are not sure if you want to know. The level of pain is so high you forget about anything else."

I second @golergka about callbacks.

The BIG pain point for me, though, looking at my 10-year-old JS, is that it's all made of "classes" built up by modifying SomeFunction.prototype, which then get wrapped in a self-invoking anonymous function and returned as an object, just so you can call `new SomeFunction()` ... `SomeFunction.actualFunction()` as if SomeFunction were a class. That and also the lack of arrow notation; modifying Function.prototype itself to use .apply() to bind events to scope (or else just an endless abyss of .bind(this) in event callbacks)...

Today I don't even write promises anymore. Using fp-ts and piping data through Task and TaskEither monads feels so much better and easier to write and maintain.

I know what most of those words mean, but I have no idea what they mean in that order. This feels symptomatic of the general state of Javascript, where I've not written any for a year or so and am now wildly out of date.

The thing is — I'm actually quite stupid. I don't even understand what a monad is. I just FP because it's a good tool. So, here's an example. I'm building an automatic storyteller on top of GPT-4 — it's a toy project to build the LLM-based functional library. Here's how the code looks, with comments: https://gist.github.com/golergka/3fdc6b9cf9717bd1c0b315925a8...

This is literally 20 lines of code, and it doesn't take that much to learn to read it easily. When I originally implemented LLM-based applications in Python, it would make about 10 times more, and all the components wouldn't be as modular. I can change the functionality of this code in a very drastic way with minimal code changes and with safety of completely statically type checked code.

Thing is: you don't read it easily. It's basically a custom DSL bolted on top of Javascript that hides actual functionality beneath an Everest of abstractions.

That is, it's a yet another library trying to force Haskell/Haskellisms into Javascript and claiming with no proof other than emotions that it's so much better and more readable than something.

Here's an actual readable version of that:

    try{
      return getTurnPromptMessages(state, action)
        .map(mkCCRequestFromMessages)
        .map(addSchemaToRequest)
        .map(handleChatCompletion)
        .map(extractFirstCompletionChoice)
        .map(extractChatCompletionMessage)
        .map(decodeSchema)
        .map(detectLocation);
    } catch (e) {
      mkMessageError(e);
    }
It can be further simplified. For example, you don't need two separate functions to extract the first chat completion message etc.

This version:

- uses existing language constructs

- can be immediately understood even by the most junior devs

- is likely to be 1000 times faster

- does not rely on an external dependency that currently has 143 issues and every two weeks releases a new version adding dozens of new methods to things

Note: one thing I do wish Javascript adopted is pipes: https://github.com/tc39/proposal-pipeline-operator