The Pipeline Operator: Cleaner Function Composition in JavaScript
Learn the TC39 pipeline operator proposal and how it transforms nested function calls into readable left-to-right chains.
The Problem: Nested Function Calls
Functional programming in JavaScript often leads to deeply nested, hard-to-read code. When you compose multiple transformations, you read them inside-out:
``javascript
// Reading order: exclaim → capitalize → trim → greet
// But written as: greet(trim(capitalize(exclaim(name))))
const result = greet(trim(capitalize(exclaim(name))));
// Or with intermediate variables (verbose):
const step1 = exclaim(name);
const step2 = capitalize(step1);
const step3 = trim(step2);
const result = greet(step3);
`
Both approaches are suboptimal. The pipeline operator fixes this by letting you write transformations in natural reading order.
The Hack-Style Pipeline Operator
The TC39 proposal uses the "hack-style" pipeline where \%\ (or another token) represents the value being piped:
`javascript
// Clean, left-to-right reading order
const result = name
|> exclaim(%)
|> capitalize(%)
|> trim(%)
|> greet(%);
// Real-world example: data transformation
const processedUsers = rawData
|> JSON.parse(%)
|> %.users
|> %.filter(u => u.active)
|> %.map(u => ({ ...u, name: u.name.trim() }))
|> %.sort((a, b) => a.name.localeCompare(b.name));
`
Practical Data Processing
`javascript
// Without pipeline — hard to follow
const report = formatReport(
aggregate(
normalize(
filterOutliers(
parseCSV(rawInput),
{ threshold: 2 }
)
)
),
{ format: 'markdown' }
);
// With pipeline — reads like a recipe
const report = rawInput
|> parseCSV(%)
|> filterOutliers(%, { threshold: 2 })
|> normalize(%)
|> aggregate(%)
|> formatReport(%, { format: 'markdown' });
`
Combining with Async/Await
The pipeline operator works seamlessly with async functions:
`javascript
const userData = userId
|> await fetchUser(%)
|> %.profile
|> enrichWithAnalytics(%)
|> await saveToCache(%);
`
Simulating Pipelines Today
While we wait for the proposal to ship, you can simulate pipelines:
`javascript
// Helper function
function pipe(value, ...fns) {
return fns.reduce((acc, fn) => fn(acc), value);
}
const result = pipe( name, exclaim, capitalize, trim, greet );
// Or with Array.prototype method chaining pattern const result = [name] .map(exclaim) .map(capitalize) .map(trim) .map(greet)[0]; ``
The pipeline operator is one of the most anticipated JavaScript proposals. It makes functional composition readable and eliminates the need for deeply nested function calls or unnecessary intermediate variables. Keep an eye on its progress through TC39.