-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support proposed ES Next "|>" pipeline operator #17718
Comments
My favourite proposal ever :( Nowadays, we can really write |
For reference, the TC39 proposal: https://github.com/tc39/proposal-pipeline-operator |
Not that the proposal is not even at stage 0 yet. If it ever is added to the language semantics and other details will likely change. |
This would be a first I think (beside some oldies like Enum and the module system) but could typescript implementing this give it more visibility and boost demand for it in the rest of the ecma ecosystem? |
Just wanted to share a workaround for the missing pipeline operator inspired by https://vanslaars.io/post/create-pipe-function/... SyncPipe with synchronous reduction// SyncPipe with synchronous reduction
type SyncPipeMapper<T, U> = (data: T | U) => U;
type SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => SyncPipeMapper<T, U>;
type SyncPipe<T, U> = (...fns: SyncPipeMapper<T, U>[]) => SyncPipeMapper<T, U>;
function createSyncPipe<T, U>(): SyncPipe<T, U> {
const syncPipe: SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => (data: T) => g(f(data));
return (...fns: SyncPipeMapper<T, U>[]): SyncPipeMapper<T, U> => fns.reduce(syncPipe);
}
// Example:
function testSyncPipe(num: number): number {
const addOne: SyncPipeMapper<number, number> = (data: number): number => {
return data + 1;
}
const syncPipe: SyncPipe<number, number> = createSyncPipe();
const syncWaterfall: SyncPipeMapper<number, number> = syncPipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = syncWaterfall(num);
return lastnumber;
} AsyncPipe with asynchronous reduction// AsyncPipe with asynchronous reduction
type AsyncPipeMapper<T, U> = (data: T | U) => Promise<U>;
type AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => AsyncPipeMapper<T, U>;
type AsyncPipe<T, U> = (...fns: AsyncPipeMapper<T, U>[]) => AsyncPipeMapper<T, U>;
function createAsyncPipe<T, U>(): AsyncPipe<T, U> {
const asyncPipe: AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => async (data: T) => g(await f(data));
return (...fns: AsyncPipeMapper<T, U>[]): AsyncPipeMapper<T, U> => fns.reduce(asyncPipe);
}
// Example:
async function testAsyncPipe(num: number): Promise<number> {
const addOne: AsyncPipeMapper<number, number> = async (data: number): Promise<number> => {
return data + 1;
}
const asyncPipe: AsyncPipe<number, number> = createAsyncPipe();
const asyncWaterfall: AsyncPipeMapper<number, number> = asyncPipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = await asyncWaterfall(num);
return lastnumber;
} Pipe with asynchronous reduction (simplified)I use this one most of the time: // Pipes with asynchronous reduction
type PipeMapper<T> = (data: T) => Promise<T>;
type PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => PipeMapper<T>;
type Pipe<T> = (...fns: PipeMapper<T>[]) => PipeMapper<T>;
function createPipe<T>(): Pipe<T> {
const pipePipe: PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => async (data: T) => g(await f(data));
return (...fns: PipeMapper<T>[]): PipeMapper<T> => fns.reduce(pipePipe);
}
// Example:
async function testPipe(num: number): Promise<number> {
const addOne: PipeMapper<number> = async (data: number): Promise<number> => {
return data + 1;
}
const pipe: Pipe<number> = createPipe();
const waterfall: PipeMapper<number> = pipe(
addOne,
addOne,
addOne,
);
// Does the equivalent of num+3
const lastnumber: number = await waterfall(num);
return lastnumber;
} I hope you will find this helpful! |
@PublicParadise way too much boilerplate :p |
While I would definitely like to see some variant of this operator in the language the perceived need for it comes from two different limitations of ECMAScript as it currently stands. The first is very hard to work around or even address in the language: the inability to extend built in objects in a hygienic manner. The second however does not need language level support at all and could in fact be rectified: the standard library can kindly be called anemic. Maximally Minimal is a complete failure. Why does it take months and months of argument to get That's one method and it should have been there from the beginning and it should be obvious that it should be added. Maybe |
By now this has a few babel implementations, which will hopefully help along the TC39 proposal: |
It's in stage 1 now |
So, any chances for this beauty getting into TS? It would be in-line with F#. <3 |
While there are exceptions, when a proposal is important to TypeScript and types, proposal are not typically implemented until they reach TC39 Stage 3 in TypeScript, as they are not stable enough to ensure that there won't be significant breakage and regressions. While none of the core team have commented on this issue yet, it wouldn't be in my opinion important enough to be considered for implementation before Stage 3. The best focus is to support the champion and proposal at TC39. |
If only TS had an option to just pipe this operator through to allow a babel with plugins to deal with it. |
@garkin: The challenge here is TS needs to understand the code to do its job of providing type safety, which doesn't combine well with random code it doesn't understand. Unless it were to get macros (#4892), in which case it'd just compile to code it does understand. But I wouldn't expect that on the roadmap quite yet, as quite a few bits of the standard library are still challenging to type atm. |
Now that Babel understands typescript you could run it through Babel then
typescript
…On 26 Oct 2017 19:01, "Tycho Grouwstra" ***@***.***> wrote:
@garkin <https://github.com/garkin>: The challenge here is TS needs to
understand the code to do its job of providing type safety, which doesn't
combine well with random code it doesn't understand. Unless it were to get
macros (#4892 <#4892>), in
which case it'd just compile to code it does understand. But I wouldn't
expect that on the roadmap quite yet, as quite a few bits of the standard
library are still challenging to type atm.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#17718 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg>
.
|
Twice the build time though :p |
Would be nice if typescript was just a Babel plugin then you'd not need to
pipe through both programs
…On 26 Oct 2017 20:16, "AlexGalays" ***@***.***> wrote:
Now that Babel understands typescript you could run it through Babel then
typescript
Twice the build time though :p
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#17718 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg>
.
|
@graingert: It's a nice option to have, i'll investigate this. |
Regarding "TS plugins" one could easily achieve the desired result with, let's say, a simple (pre)transpiler for the pipe operator that understands TS syntax and produces it's strong typed equivalent of the statement. It would compile just fine with type checking and whatnot. A webpack configuration for that could look something like this:
The only challenge, as pointed by @garkin, is that TS service wouldn't be able to correlate transpiled parts to the original source file, then IDEs that uses the service wouldn't work properly even if they already recognize the operator (ES Next syntax enabled or something). Perhaps if we create a NFR (or maybe there's already one?) for TS service to support cumulative source maps to be applied between the source file and the transpiled result that is feed to the compiler, this and other plugins would be possible without affecting the rest of the community and, most importantly, without adding more complexity for the core team to deal with. Also, I can't tell how much #13940 is related to this but its apparently a good start towards more complex plugins. However it seems to me that the source map approach still much simpler alternative since a minimalistic (pre)transpiler wouldn't need the project context for most cases as it would be fairly easy to just extract the type notation blocks (if any) from the statement raw text and then rewrite it in a way that control flow will be able to imply the specific I/O types for the transpiled part. Last but not least, could anyone please point me out to the official thread (if any) regarding this kind of plugins? |
I need to say i realy appreciate calm way of introducing new proposals and prefer the monolithic Typescript and LessCSS tooling much more, than Flow+Babel and Post-CSS special plugins olympics. It's a customizabilty and a speed of getting new features in cost of bloating fragmentation and an area of expertise. The pipe operator is just like an entry drug to the functional world, it makes me say and wish a weird things. So, there are #14419 and even some useful practical implications already. Should not be hard to integrate those with
|
@PublicParadise or just use lodash's anyway, this would be so awesome to see to be supported in TS. I love the functional patterns JS supports (especially with TS' type inference), but some patterns don't read very nice. This would be huge as big TS libraries like RxJS and IxJS are moving towards point-free functional composition over prototype extension/inheritance, it makes for way better tree shaking and support for custom operators. |
@felixfbecker You mean ramda's |
It actually works decently well if your functions and chains are not super crazy: |
Let me qualify 'not super crazy' there: things break down if your functions have generics (see typed-typings/npm-ramda#86), e.g. |
Also, let's be clear, the proposal is Stage 1. The core team are getting even more shy about introducing things before Stage 3. Decorators are part of the example. Even though they were marked as experimental, we all went ahead and enabled that flag and wrote all of our production code using them. The proposal now has bounced around and there are some fundamental breaking changes in the syntax and semantics that are going to mean we are all going to have to refactor our code which puts the core team in a tight situation, because if they only support the final syntax than everyone is broken the day they release it, or if they keep the legacy stuff, other changes in the compiler could make it challenging to support the two syntaxes, and eventually you want to get rid f the old stuff, but when... 💥 💥 So the best thing to do with standards based features like this, isn't to debate TypeScript's support or lack of support here, it is to find you friendly local TC39 rep and advocate that this feature is really important to you as well as participate in the proposal conversation linked to above on GitHub. The quicker the semantics get resolved and the quicker it gets to Stage 3, the quicker we can all have nice things! |
Now that |
Can we have someone from TS team to shed some light on this request? |
The have, they have tagged it A comment from them won't change anything. Do you think they are secretly working on it behind the scenes, waiting to spring it on the community? They often won't input on an issue if there is nothing to add... There is nothing to add to what has already been said. |
A minute of silence for the fallen hero, the bind operator |
Well I guess it's in the eye of the beholder, as I prefer |
hail to the king! |
And here I thought it was a pipe dream |
Pipeline is essentially a simple use case of the Identity Monad. Also, Anyway, looking forward to seeing this in Typescript. |
Although having pipeline would be helpful, I feel it would be possible to offer the ability to define custom operators (functions whose name may include special chars, and whose first param is on their left) via a compiler transformer. Anyone interested in trying this with me, or have some background on this?
…On Fri, Aug 10, 2018, 02:53 Babak ***@***.***> wrote:
Pipeline is essentially a simple use case of the Identity Monad. Also,
pipe is usually compose in reverse whereas pipeline is more like a pipe
that is invoked right away.
Anyway, looking forward to seeing this in Typescript.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#17718 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg>
.
--
|
Infix functions ftw
On Thu, 9 Aug 2018, 23:35 Ben Beattie-Hood, <notifications@github.com>
wrote:
… Although having pipeline would be helpful, I feel it would be possible to
offer the ability to define custom operators (functions whose name may
include special chars, and whose first param is on their left) via a
compiler transformer. Anyone interested in trying this with me, or have
some background on this?
On Fri, Aug 10, 2018, 02:53 Babak ***@***.***> wrote:
> Pipeline is essentially a simple use case of the Identity Monad. Also,
> pipe is usually compose in reverse whereas pipeline is more like a pipe
> that is invoked right away.
>
> Anyway, looking forward to seeing this in Typescript.
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <
#17718 (comment)
>,
> or mute the thread
> <
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
>
> .
>
--
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#17718 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg>
.
|
the idea of infix functions for typescript is almost as old as typescript: #2319 |
I know a lot of people want this really bad, but I believe TypeScript should not implement any extra operator as long as they are not in stage 3. Things can change and of course there are some exceptions. |
I think it would be worth trying as a compiler transformer, just to allow the community to explore the idea, and to measure popularity. It's a well-defined feature in other functional languages, so might be quite safe to explore. |
@BenBeattieHood We're in the process of implementing this in babel, so you'll be able to test it there. If you do test it in a compiler transformer, definitely take a look at the current proposals, as there are a few forms of the pipeline operator we're considering. |
I think it would need a lot of thought about how its used; specifically with regard to typing things like: function where<T>(predicate: (x: T) => boolean) {
return function* (items: Iterable<T>): Iterable<T> {
for (const item of items) {
if (predicate(item)) {
yield item;
}
}
};
}
[1, 2, 3] |> where(x=>x> 1) at the moment with |
Or we can see it another way: should it get released, It will prioritize some of the inference issues TS has 👍 |
If you follow the spec and babel news, the spec is not set yet. There are 2 proposals. Im sure the typescript team will add support when the spec is finalized |
iirc JS calls these "methods". |
@tycho01 Your comment is probably tongue in cheek, but I think these aren't quite the same thing. You can't just export a binary function from somewhere and apply it infix to two values; knowledge about every function that's ever going to manipulate the value must be grafted onto the value itself, either as a direct property or on the prototype. This is pretty inconvenient in practical scenarios. |
Babel parser now supports smart pipeline proposal. |
Any updates? |
🤦♂️ TypeScript does not implement proposal until they reach Stage 3. The pipeline operator is currently Stage 1 and has serious issues. That information has been provided multiple times in this thread. |
an example of serious issues please? |
|
Yes, that is what I consider a serious issue. |
Going to lock this one since all threads in Waiting for TC39 status tend to just go in circles. Ping! |
Marking this as closed since there's nothing for us to do until something happens at TC39. We're working with some other members to continue to iterate on the active proposals, so please contribute feedback there until that proposal (or its kin) reaches stage 3. |
No description provided.
The text was updated successfully, but these errors were encountered: