Description
I have a request/proposal to consider. I recognize it would almost certainly be made into its own proposal, but since it's deeply related to |>
I wanted to raise it here first. The |>
operator provides a clean way to chain operations, but it lacks built-in support for handling different data shapes or cases within the pipeline. I propose extending the pipe operator to support inline pattern matching, which would enhance its expressiveness and flexibility.
I propose adding a match%
keyword that can be used within a pipe chain to perform pattern matching. Here's an example of how it might look:
data |> match% {
case [head, ...tail] => processHead(head) |> concat(tail),
case { type: "user", name } => greetUser(name),
case { type: "admin" } => adminDashboard(),
default => handleUnknownData
}
In this syntax, match%
initiates pattern matching within the pipe, with case
clauses defining patterns to match against. The right side of =>
in each case can include further piping. This approach allows complex branching logic within pipes without breaking the flow, makes data transformation pipelines more declarative and easier to understand, combines the power of pattern matching with the composability of pipes, and provides a clean way to handle different data shapes or error cases in pipelines.
The pattern matching in pipes could also support destructuring, as shown in this example:
fetchUserData()
|> match% {
case { name, age, friends: [bestFriend, ...otherFriends] } =>
% |> formatUserProfile
|> addBestFriendInfo(bestFriend)
|> listOtherFriends(otherFriends),
case { error } =>
% |> logError
|> displayErrorMessage
}
It could also integrate well with async operations:
fetchData()
|> await%
|> match% {
case { status: "success", data } =>
% |> processData
|> updateUI,
case { status: "error", message } =>
% |> logError
|> showErrorNotification
}
And support guard clauses for more complex conditions:
validateUser(user)
|> match% {
case { age } when age >= 18 =>
% |> grantAccess
|> logAdultUser,
case { age } when age < 18 =>
% |> restrictAccess
|> notifyParents,
default => handleInvalidUser
}
While this proposal offers significant benefits, there are challenges to consider, including syntax complexity, performance, integration with existing patterns, and tooling support. To move forward, we should gather community feedback, develop a detailed specification, create a basic implementation, and discuss with the TC39 committee.
I welcome thoughts and ideas on this proposal. How do you see this fitting into JavaScript? Any overlooked use cases or challenges?