
TypeScript support for ES Next pipeline operator - valera_rozuvan
https://github.com/Microsoft/TypeScript/issues/17718
======
viksit
Greenspuns tenth rule: “Any sufficiently complicated C or Fortran program
contains an ad-hoc, informally-specified, bug-ridden, slow implementation of
half of Common Lisp.”

I’ve always wanted a clojure style thread operator [1] in other languages :)

[1]
[https://clojure.org/guides/threading_macros](https://clojure.org/guides/threading_macros)

~~~
emmanueloga_
It is interesting to note the overhead it has to define such simple construct
in JavaScript. Pages and pages of a spec, all the work to herd ppl behind the
proposal, etc.

In Clojure, the threading macros are awesome and they are not even a language
construct, just some ~10 lines of code per macro! [1]

In ML, the pipe operator is even shorter:

    
    
        `let (|>) x f = f x`
    

1:
[https://github.com/clojure/clojure/blob/4ef4b1ed7a2e8bb0aaaa...](https://github.com/clojure/clojure/blob/4ef4b1ed7a2e8bb0aaaacfb0942729252c2c3091/src/clj/clojure/core.clj#L1669-L1699)

~~~
andreareina
I used to think the same, until it was pointed out to me that the semantics
have to be nailed down exactly, so that conforming implementations (e.g.
Chrome/FF) do the same thing. This includes figuring out how (if at all) it
works with generators and async functions, if you want to support implicit
lambdas, etc[1]. Clojure and ML (and related languages I imagine) have the
advantages that it is expressible in code which at least makes the
specification part simpler.

Fortunately the simple version is easily approximated, I have this sprinkled
in various files where it's useful:

    
    
        const pipeline = (val, ...funcs) => funcs.reduce((a, b) => b(a), val);
    

[1] [https://babeljs.io/blog/2018/07/19/whats-happening-with-
the-...](https://babeljs.io/blog/2018/07/19/whats-happening-with-the-pipeline-
proposal)

------
maxfurman
What happened to the bind operator (::)? I do miss threading macros from
Clojure but I don't see them as solving a real problem in the javascript
language. A shortcut for binding `this`, on the other hand, would have saved
me a lot of time wondering why my React component methods weren't working
correctly.

~~~
adregan
You can use the fat arrow syntax to implicitly bind a function to this:

    
    
        handleChange = e => this.setState({ value: e.currentTarget.value })

~~~
rpeden
Wouldn't that be problematic if you're binding lots of handlers, though? It
seems like the fat arrow syntax here is creating a new anonymous function for
every instance of the handler.

And if you've got a list of tens or hundreds of items, and you want a click
handler for each, you quickly get to the point where all the extra overhead
matters.

Like, for instance, in a React render function you could have

    
    
      {things.map(thing => {
        return <Thing onClick={e => this.handleClick(thingId) } />
      })}
    

or

    
    
      {things.map(thing => {
        return <Thing onClick={this.handleClick.bind(this, thingId)} />
      })}
    

But option #1 would be a lot less efficient if you've got lots of things,
since it's creating a new closure that calls the instance method instead of
just pointing at the instance method like snipper #2 does.

I still see lots of people recommending #1 for this exact scenario, though.
Maybe I'm just wrong, or maybe stuff like this is why I see so many SPAs
consuming shocking amounts of memory.

I grant that using the fat arrow is probably fine for the scenario you
mentioned though, with something like a text field. I don't think I've seen
many pages with so many text fields that the extra overhead would even make a
difference.

~~~
alxlu
Having .bind inside a JSX prop also creates a new anonymous function on each
render.

To avoid it, you can do (sorry for bad formatting):

    
    
      class Thing extends React.Component {
        handleClick = (thingId) => {
          this.setState(/*stuff*/);
        }
        render() {
          return <div>{things.map(thing => <Thing onClick= 
       {this.handleClick} />)}</div>
        }
      }
    

You can also bind handleClick inside the constructor without the arrow.

    
    
      constructor(...args) {
        super(...args);
        this.handleClick = this._handleClick.bind(this);
      }
      _handleClick(thing) {
        // stuff
      }

~~~
mercer
The latter version seems to be the one I most commonly see, except
_handleClick() is just handleClick() repeated. Am I correct in assuming this
is considered idiomatic at this point?

~~~
antonkm
Yes, I'd say so.

~~~
mercer
Is this better somehow? I feel like I should know this, but it's Friday night
and I'm tired, but isn't the constructor fired on every instance of the
component? And if so, is this a better approach for any particular reason
other than clarity?

~~~
aenigmaclamo
It is fired on every instance of the component. However, if you create the
arrow function in the render function, it'll be created for every render.
Since React keeps the component instances around between renders, it can be a
lot better.

~~~
mercer
Ah, that makes sense. Do you by any chance know of any articles that go
further into how this works?

~~~
RunawayGalaxy
[https://pbs.twimg.com/media/DZ-97vzW4AAbcZj.jpg:large](https://pbs.twimg.com/media/DZ-97vzW4AAbcZj.jpg:large)

~~~
mercer
Perfect!

------
alvis
Note that the proposal for a pipeline operator is still in its early day. In
fact, there are two proposals ([https://babeljs.io/blog/2018/07/19/whats-
happening-with-the-...](https://babeljs.io/blog/2018/07/19/whats-happening-
with-the-pipeline-proposal)) and so far there's no clear winner. Seems like
there's still a long way to go.

Anyway, which style do you prefer?

~~~
deckar01
Neither. Just use a function. You don't need a dedicated operator in the
language's syntax to composite functions.

    
    
        const foo = pipeline(
            bar,
            baz,
            x => x + 1,
        )
        foo(42)

~~~
jahewson
Now try writing the type declaration for your pipeline function...

~~~
deckar01

        pipeline : (...fns : Function[]) => Function

------
dvlsg
Don't they still have to wait for the spec to finalize / hit stage 3?

Don't get me wrong, I'm super excited for this functionality because I love it
in languages like F# and Elixir, but it looks like the pipe proposal is still
stage 1.

[https://github.com/tc39/proposals/blob/master/README.md](https://github.com/tc39/proposals/blob/master/README.md)

~~~
k__
While I think this is a risky move, I had the impression that the ratification
of new features was mainly based on the implementations.

So, first the runtimes/compilers implement it and _then_ it gets into the
spec.

TypeScript sees itself as a superset of ECMAScript, so its ECMAScript parts
are just another implementation of the spec, like Node, Babel and the browser
engines.

------
skybrian
It seems unfortunate that JavaScript is evolving so quickly these days. There
is more syntax than anyone who isn't a full-time web developer will be able to
remember.

~~~
lucideer
There's been a lot of new features added in ES6+ but not a huge amount of new
syntax overall (a lot of the new features are things like array and object
methods, etc.)

All of the new syntax is technically optional, but at least some percentage of
it just makes it easier for newer/less-experienced devs to write things: e.g.
classes as simplified syntactic sugar around prototype-based inheritance
models, or function parameter spread operators to make learning how to
arguments.whatever unnecessary and generally make code for dynamic argument
lengths easier to understand.

No matter when you started learning Javascript there would have been parts too
complex or obscure to learn immediately (the prototype-based inheritance model
is something I think a lot of full-time professional JS devs don't fully
grok). There was always things you learn first and things you learn later.
With the new syntax, I think now the things* you learn first are just more
likely to be immediately useful.

* where "things" excludes learning how to master every trending new library—that is a part of Javascript that isn't improving unfortunately.

~~~
meandmycode
I find this to be a bit of a cop out, there's still less syntax than something
like C# or Java, and plenty of developers are ok with those.. JavaScript went
through years of nothing and then sudden change.. if you were only casually
interested in it (say, a backend developer who just puts some js together)
then criticizing seems unfair.. you can continue to write the exact same code,
but expect those who write it as their primary language care a hell of a lot
more about it being succinct and powerful.

------
AndrewDucker
I was hoping we'd get something like PowerShell pipelines, which work on
iterators, passing each item through as it's generated.

Those are incredibly powerful, and as a lot to the language, whereas this just
seems like fairly simple syntactic sugar.

