- Published on
Functional Programming with TypeScript
- Authors
 - Name
- Garfield Zhu
- @_AlohaYo_
 
 
@Author: Garfield Zhu
As a declarative programming paradigm, Functional Programming leverages the math theory and type system to build the program with pure functions in a modular manner.
As a good language supporting functional paradigm, as well as a strong type system, TypeScript is ideal for practising FP. In this article, we just introduce and demo some useful snippets of FP in TypeScript.
Related libraries:
- fp-ts is the most recommended to be used in ts. Read code conventions for a best practise. 
- Run with Deno runtime, like: - deno run memoize.ts
- ramda.jsis one of the common FP library for js. Refer to official doc and a tutorial in Chinese.
Keep IMMUTABLE
The best practise in FP is using immutable variables anywhere if possible.
In TypeScript, use const for type declaration and readonly for properties of type/interface and args of functions as much as possible. Avoid using let or var declaration if they are not a must. (Actually, there should always be a way to abandon a mutable variable)
Example:
declare const a : number
const b = a > 0 ? 'positive' : 'negativeOrZero'   // $ExpectedType: 'positive' | 'negativeOrZero'
let b = a > 0 ? 'postive' : 'negativeOrZero'     // $ExpectedType: string
Pure function
- Cacheable 
- Portable / Self-documenting 
- Testable 
- Reasonable 
- Concurrency 
Curry
TypeScript is not born to support curry. Node package like [Rambda](https://github.com/ramda/ramda) provides a good implementation of curry, but since we are on Deno with TypeScript, it seems not very direct for us to use it, neither give a cool implementation of it in TS.
A sample for a currying step by step: How to master advanced TypeScript patterns
Also, we can look forward for the proposed feature Variadic Kinds, which will make it easier to define a typed curry function.
Fortunately, Denofun serves a group of useful utilities for FP including curry.
Example:
import curry from "https://deno.land/x/denofun/lib/curry.ts";
const greet = (name: string, age: number) => `hello, I'm ${name} and I'm ${age} years old`;
const curriedGreet = curry(greet);
curriedGreet("Tomasz")(26) 
Practises: using curry
Compose
- Associativity - const associative = compose(f, compose(g, h)) == compose(compose(f, g), h) // Both have: // associative(x) = f(g(h(x)))
- Pointfree "Never say your data" - // not pointfree, for data `word` is mentioned const snakeCase = (word: string) => word.toLowerCase().replace(/\s+/ig, '_') // pointfree const pointfreeSnakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);- Reference: Favoring Curry
- Blog: using pointfree
 
- Debug It could be hard to find the error place in a pointfree style, since we throw all the parameters away Like this: - const dasherize = compose(join('-'), toLower, split(' '), replace(/\s{2,}/ig, ' ')) dasherize('The world is a vampire') // TypeError: Cannot read property 'apply' of undefined- We can simply use a curried - tracefunction to telemetry the parameters for debugging:- const trace = curry(function(tag, x){ console.log(tag, x) return x }) const dasherize = compose(join('-'), toLower, trace("after split"), split(' '), replace(/\s{2,}/ig, ' ')); // after split [ 'The', 'world', 'is', 'a', 'vampire' ] // Correct: const dasherize = compose(join('-'), map(toLower), split(' '), replace(/\s{2,}/ig, ' ')) dasherize('The world is a vampire');
Moreover, we have a similar pipe function, which also combines the functions. The function parameter is called from right to left in compose, but left to right in pipe.
Practises: using compose
Functor
A Functor is a type that implements map and obeys some laws
Typically, we use pointed function which contains a of function for instantiating a functor.
  Container.of(3)
  // Container(3)
  Container.of(3).map(x => x + 1)
  // Container(4)
Applicative Functor
"Applicative functor" is a kind of "pointed functor" which implements ap function.
Function ap should apply the value of a functor to the value of another functor.
It means: F.of(x).map(f) == F.of(f).ap(F.of(x))
  Container.of(add(2)).ap(Container.of(3))
  // Container(5)
  Container.of(2).map(add).ap(Container.of(3))
Use applicative functor will make a curried function in functor being used like a a normal function call:
  Maybe.of(add).ap(Maybe.of(2)).ap(Maybe.of(3))
  // Maybe(5)
  Task.of(add).ap(Task.of(2)).ap(Task.of(3));
  // Task(5)
Reference
Mostly adequate guide to FP (in javascript)