Reading — step 1 of 5
Learn
Pipelines: Map, Filter, Reduce
Loops tell the computer HOW to iterate. filter, map, and reduce state WHAT you want: keep these, transform them, collapse to an answer. Once the shape clicks, most array code becomes a short, readable pipeline — and TypeScript type-checks every stage of it.
The three stages
const nums: number[] = [1, 2, 3, 4, 5];
nums.filter(n => n % 2 === 0); // [2, 4] keep where true
nums.map(n => n * n); // [1, 4, 9, 16, 25] transform each
nums.reduce((a, b) => a + b, 0); // 15 fold into one value
filterreturns a NEW array containing the elements for which the callback returned true. Same element type, possibly shorter. The original array is untouched.mapreturns a NEW array of the callback's return values — always the same length, possibly a different type (nums.map(n => String(n))isstring[]).reducethreads an accumulator through the array: the callback is(accumulator, element) => newAccumulator, and the second argument is the accumulator's starting value. The result is a single value.
Chaining — with the compiler watching
const result: number = nums
.filter(n => n % 2 === 0) // number[] — evens: [2, 4]
.map(n => n * n) // number[] — squares: [4, 16]
.reduce((acc, n) => acc + n, 0); // number — sum: 20
TypeScript infers the type flowing out of each stage. If your map callback accidentally returned a string, the reduce below it would fail to compile immediately — a mistake cannot silently flow downstream. That is the concrete upgrade over writing the same chain in plain JavaScript.
Trap 1: reduce without an initial value
[].reduce((a, b) => a + b); // TypeError: Reduce of empty array with no initial value
[].reduce((a, b) => a + b, 0); // 0 — safe
With no initial value, reduce seeds the accumulator from the first element — and an EMPTY array has no first element, so it throws at runtime. Any pipeline whose filter might reject everything must give reduce an explicit initial value.
Trap 2: forgetting to return
Concise arrow bodies return automatically; arrow bodies with braces need an explicit return:
nums.map(n => n * n); // fine — implicit return
nums.map(n => { n * n; }); // BUG — returns undefined for every element!
nums.map(n => { return n * n; }); // fine — explicit return
The buggy version produces [undefined, undefined, ...], which turns all later arithmetic into NaN.
Your exercise
The starter has the whole pipeline scaffolded with placeholder callbacks:
const result: number = nums
.filter((x) => true /* TODO: keep only evens */)
.map((x) => x /* TODO: square it */)
.reduce((acc, x) => acc /* TODO: add x to the sum */, 0);
Replace the three TODOs: keep only even numbers (x % 2 === 0), square them (x * x), and accumulate the sum (acc + x). The starter already prints result.
Mistakes the grader will catch:
- Leaving the filter as
true: for input1 2 3 4 5you would sum the squares of everything (55) instead of just the evens — the expected output is20. - Leaving reduce returning bare
acc: everything collapses to0regardless of input. - Deleting reduce's initial
0: the hidden test1 3 5 7filters down to an EMPTY array, and reduce with no initial value crashes at runtime — the expected output there is0, which only happens with the initial value in place.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…