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
Add support for using functions as pipes #55471
Comments
Prior discussion: #24559 |
tl;dr; I absolutely do share the sentiment, although we need to dig deeper to see where pipes are really useful and creating them is worthwhile. For some cases, though, creating a pipe is just a pure overhead and one should use a function or a computed instead. Pipes - the good partsWhile the
The pipes are brilliant for library authors that want to create fairly complex pipes with dependencies, especially pure pipes. Pipes - the alternativesPipes without constructorsNon-pure pipesFirst of all, if a given pipe doesn't have any constructor and is not pure there is not much reason for it to be a pipe - just create a regular TypeScript function. Pure pipesThe main benefit of pure pipes without a constructor is their memoization capability. I do very much agree that in this particular case a function as a pipe would be very useful. For applications using signals a Pipes with a constructorPipes that do have a constructor indicate that there is some creation / initialisation logic and in this sense having a class for a pipe is useful. We could use a factory function instead but this is just introducing a different way of doing things without clear benefits. Pipes as functionsGiven the above discussion we can see that registering functions as pipes would be mostly beneficial for pure pipes without a constructor. So if we go down this path it would cover only a subset of use-cases and introduce 2 way of doing things. But assuming that we do want to go down this path, let's look at the possible API designs Technical solutionsDecoratorsIn #24559 the suggestion was to use a decorator on a function, which is, sadly, not supported in TS / upcoming TC39 spec. Instance methodsThis issue suggest using a directive's instance members as a pipe. This is challenging since there is no place to specify pipe's metadata - if it is pure or not. This could be done with a decorator, ex.: @Component({
...,
template: `{{'hi' | upper}}`
})
class MyComponent {
@Pipe({pure: true})
upper(value: number): string {
return value.toUpperCase();
}
} The drawback here is that those pipes are tied to the instance of a given component and are no longer easy to share. |
Given the background in my previous comment, I'm not sure if there is enough benefit of implementing an alternative syntax for pipes. What we really seem to want here is the memoization aspect of pipes but we do have signals now. |
There is also the question of #43485 - pipes are currently a completely custom syntax. If we move in the direction of making Angular expressions just plain TypeScript, clearly pipes don't fit into that story. |
One downside of computeds is how they need to be stored somewhere, i.e. they can't be temporaries. That can be a limitation in e.g. An idle thought could be to have some syntax to declare a computed within the template, such that computeds can be declared in the context of an embedded view. |
For now we created a memoize pipe that accepts a function and runs it. I do think what @JoostK said is a good idea though I am not sure how to do it and whether it is actually a part of template local variables (another issue) |
ngxtension callPipe / ApplyPipe can be used as a workaround. |
Which @angular/* package(s) are relevant/related to the feature request?
core
Description
Currently, in order to create a custom pipe, there is a good amount of boiler-plate code. You need to add the
@Pipe
decorator to an entire class that you create, just so you can extendPipeTransform
and implement what often ends up being a small transformation or piece of logic.This is reminiscent of the old
CanActivate(Children)
andCanDeactivate(Children)
classes, which were deprecated in favor ofCan(De)ActivateFn
. I am suggesting making a similar change for pipes, which would allow devs to reduce the amount of boilerplate code they have to write as well as allowing devs to keep small or extremely specific pipes within the class files they're used, since the function could just be defined on the class.Proposed solution
Creating a
PipeFn
class which defines the inputs/outputs required for a function to work as a pipe, and allow functions to be used as a pipe in lieu of entire classes.Alternatives considered
An alternative would be modifying the
@Pipe
decorator so that it can be used on classes or functions, or creating a different decorator for functions to mark them as pipes.The text was updated successfully, but these errors were encountered: