9 Useful Functional Programming Solutions You Can Learn (in TypeScript and Node)
9 Useful Functional Programming Solutions You Can Learn (in TypeScript and Node)
Coding examples that are easy for web developers to understand.

Source: Unsplash
For Portuguese readers: Thanks to Alison Miazaki who translated my story into Portuguese: 9 Soluções práticas em programação funcional para você saber (em TypeScript e Node).
We’ve all been there as software developers: We’re writing or reviewing a snippet of code. Then out of nowhere, our intuition tells us that we could further simplify our code. Or, if we are familiar with imperative programming, there seems to be a “functional” way to solve the problem. The “functional” solution is at our fingertips, but we somehow can’t write it down.
I wrote this article to help unblock myself from this type of situation. After all, we can get inspiration from anywhere. It’s a matter of finding the right hints to get to that solution. The closer the hint is to the solution we are looking for, the better.
We’ll go through a set of common coding tasks ordered by the simplicity of the problem. I used TypeScript with Node 10 to test each solution.
1. Mocking in Unit Tests
Problem
When testing an async function, you want to use mock data when running your tests locally.
Non-functional approach
Use anif-elsestatement to determine which function to run, whether async or mocked.
Functional approach
Assign the async and mocked function to their variables. Use a ternary operator to determine which function to use based on the current environment.
Code snippet by the author.
2. A/B Testing or Experimentation
Problem
You want to show two or more different variants of your web application: variants A and B.
Non-functional approach
Use anif-elsestatement to determine which variant to show.
Functional approach
Assign your display functions to their variables. Create an object to map the function variables to their corresponding variant. Use the variant as the object key and function variables as the object value. Display the variant using the object hashmap.
Code snippet by the author.
3. Execute a Series of Functions to a Piece of Data
Problem
You have many functions that take an object, execute a series of updates to that object, and return an updated or transformed object:
Code snippet by the author.
Non-functional approach
You can execute the function line by line. For example, you initialize anemployeeobject with anid. Then a series of functions will update theemployeeobject and return the updatedemployeeobject.
Code snippet by the author. The code executes the functions starting line 17.
The code above gets the job done. You are applying each function line by line to the mutatingemployeeobject. Imagine if you need to add a new function. You could add a new line to call the function and pass theemployeeobject as an argument. Not bad, but we can do better.
Functional approach
The functional way is to assign the functions in an array, iterate through that array usingforEach, and apply each function to the argument. Note that theemployeeargument to pass after applying the first function in the array will be the returned value of the previous function. You use the functions in the same order in which they are positioned in the array.
Code snippet by the author. Line 17 assigns the functions in an array.
If you need to add another function to execute, add another entry in thepersonFunctionsArrayarray. You don’t need to reassign the returned value toemployeeand pass it as an argument to the next function.
4. Simple Calculator
Problem
You want to implement a simple calculator that accepts two numbers.
Non-functional approach
The object-oriented approach is to create aCalculatorclass that contains the calculation operations as methods within that class, which areaddandsubtract. If you want to add more operations, you will update the class to add each operation’s corresponding method. Another way is to write an individual function for each operation. For instance, implement thecalculateSum()andcalculateDifference()functions.
Functional approach
Create acalculate()function that accepts an operation function (e.g.add()) as an argument that will perform the calculation you want. The function that calculates is also self-contained and you can use it without it being passed as an argument.
Code snippet by the author. Pass the operation function as an argument to the calculate function.
5. Conversion Calculator
Problem
Convertmeterinto the imperial unitsmile,yard,foot, andinch. These unit conversion functions take the valuexinmeterand return the converted value in an imperial unit formatted with its corresponding symbol.
Non-functional approach
Write a function for each conversion.
Code snippet by the author. Conversion starts on line 6.
The duplicated code in the conversion functions is evident in the example above. Multiplication and string formatting in each function is repetitive.
Functional approach
Try to solve this by creating a function that will handle the different conversions while maximizing code reuse between functions with slightly different behaviors.
ThecreateConverter()function below accepts the conversion valuevand symbolsarguments. It returns a function that takes anxargument, which is the value that you want to convert.
const createConverter = (v: number, s: string) => (x: number) => `${x * v} ${s}`Reuse thecreateConverterfunction above to form the conversion functions.
const meterToMile = createConverter(0.0006213689, 'mi')
console.log(meterToMile(1000))You are maximizing reuse while keeping your code maintainable.
6. Validate Function Arguments
Problem
You have a function that performs a subtraction operation, given aminuendand asubtrahendas its arguments, and returns thedifference. The returned value should be non-negative numbers only. Therefore, you will need to validate your arguments such that theminuendshould always be greater than or equal to thesubtrahend:minuend >= subtrahend.
const minus = (minuend: number, subtrahend: number): number => minuend - subtrahendAccording toClass Ace:
- “
minuend— This is the biggest number, or the whole, from which a part will be taken away.
-
subtrahend— This is the part that is taken away from theminuend.
- Difference — This is the part that is left over after subtraction.”
Non-functional approach
The typical way to validate the arguments would be to add a conditional early return or exit.
The code above works. However, the function is doing more than one thing. Instead of only returning the difference, it also validates the arguments. It violates the single-responsibility principle inSOLID.
Functional approach
First, create a separate function for validating the arguments.
const minus = (minuend: number, subtrahend: number): number => minuend - subtrahendCreate theminusPositiveDifference()function that calls theminuendGreaterThanSubtrahend()validation function with theminus()function as its argument. ThisminusPositiveDifference()will then be called to ensure that your arguments are validated first before performing the subtraction.
const minusPositiveDifference = minuendGreaterThanSubtrahend(minus)Each function is doing one thing while solving the problem.
Code snippet by the author. A functional approach to validate arguments while keeping the code compliant with the single-responsibility principle.
7. Word Counter
Problem
You have a string of words or a poem assigned to a variable. You want to count the number of times a word has occurred in the string. This problem is similar to having an array and wanting to count the number of times certain elements appear in the array.
const poemInput: string = `Hold fast to dreamsFor if dreams dieLife is a broken-winged birdThat cannot flyHold fast to dreamsFor when dreams goLife is a barren fieldFrozen with snow`.replace(/(\r\n|\n|\r)/gm, ' ').toLowerCase()To simplify the string, replace the line breaks with spaces and transform them to lowercase.
Non-functional approach
Use a hashmap to keep track of the number of occurrences of the words.
Functional approach
Usereducewith thewordCounterhashmap as the accumulator andwordas the element to process.
Use a spread operator to extract the key and value of thewordCounterhashmap.
Use a ternary operator to check if the word is already in the hashmap. If it is in the hashmap, increment the value. Otherwise, assign1, which means that the word has appeared for the first time.
Code snippet by the author. The functional solution is more compact and easier to read if you are already familiar with functional programming.
8: Finding Anagrams
Problem
“An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.” —Wikipedia
Given a word, you want to find its anagram(s) from an array of words provided.
For example, you have this array of words with its corresponding anagram in the comment.
const words: Array<string> = [ 'rat', // tar 'car', // arc 'below', // elbow 'taste', // state 'cried', // cider 'study', // dusty 'thing', // night 'chin', // inch 'grab', // brag 'act', // cat 'robed', // bored 'vase', // save 'glean', // angel 'desserts', // stressed]
The input can be one of the possible anagrams.
const input: string = 'save'Non-functional approach
There are many examples of non-functional solutions to this problem online, so I will not cover them here.
Functional approach
You can solve this with a combination of the JavaScript built-infilterandreducefunctions. Repurpose the samecountWordsfunction in example #7 that usesreduce, but instead of counting words, you are now counting letters in a word.
const countLetters = (word: Array<string>) => word.reduce(
(letterCounter: Map<string, number>, letter: string) => ({
...letterCounter,
[letter]: letterCounter[letter] ? letterCounter[letter] + 1 : 1,
}),
new Map<string, number>()
);Use thefilterfunction to filter words that have the same letters and length as yourinputvalue.
const findAnagrams = (word: string, words: Array<string>): Array<string> => {
return words
.filter(entry => hasSameLetterCount(word, entry))
.filter(anagram => anagram !== word);
}The final solution will be the following:
Code snippet by the author. The solution uses a combination of filter() and reduce() functions.
9. Form Validation
Problem
You have a form that accepts input from the user, and you need to validate the input. Some simple validation criteria can include a username that is at least three characters long or the user needing to enter a valid email address.
const currentInputValues: Object = { username: 'ar', email: 'me@',}Non-functional approach
There are many examples of non-functional solutions to this problem online, so I will not cover them here.
Functional approach
Start with a hashmap of input criteria where the key is the field and the values are arrays of input criteria. For example:
ThehasMinCharactersandhasValidEmailfunctions check the input and return an error message.
Use a combination ofreduceandmapto accumulate the error messages returned by testing each input against its corresponding validation criteria. Usefilterto exclude empty strings.
Code snippet by the author. The solution uses reduce, map and filter.
Conclusion
To recap:
- Examples 1, 2, and 3 are good examples of how you can treat functions as data.
- Example 4 shows that you can use functions as arguments.
- Example 5 shows that you can use functions as return values.
- Example 6 shows how you can use higher-order functions.
- Examples 7–9 use a combination of the previous concepts plus built-in functions like
map,reduce, andfilter.
I’m not suggesting that you should always use the functional solutions outlined above when you encounter the same problems. Sometimes it’s a matter of preference or coding style. It will also help if you consider other factors before writing down your solution, like your existing code base, team members, and coding guidelines.
I hope your journey with functional programming has been fun so far!
You can find the code examples used in this article below: