Exploring if you can have your cake and eat it to.
TypeScript continues to fall flat on its face for most higher order functions. Maybe I just don’t know how to use it correctly (after years living with it on a regular basis ― in which case, they really need to improve usability, documentation, or both), but I still don’t know how to properly type the map operation in TypeScript, and it seems to be oblivious to anything going on in a transducer. It fails to catch errors, and frequently complains about errors that aren’t really errors at all.
One interesting, and more complicated, pattern is a functor.
A functor data type is something you can map over. It’s a container which has an interface which can be used to apply a function to the values inside it. When you see a functor, you should think “mappable”. Functor types are typically represented as an object with a.map() method that maps from inputs to outputs while preserving structure. In practice, “preserving structure” means that the return value is the same type of functor (though values inside the container may be a different type).
― Eric Elliot ― Functors & Categories
Edit 1/4/19: Turn out that in my first pass at this, I neglected to return a functor from the map function; big mistake . Also, added some more complex mapping functions, especially conversion that switches types (from number to string) to make the problem more challenging.
Let us rewrite this code in TypeScript :
note: One of the complicated parts of TypeScript is Generics ; assuming the reader is familiar with this concept.
In the above TypeScript example, we again deliberately misuse the c functor, trying to multiply a string by 2. This time, however, we get a compile time error (as shown in my editor, Visual Studio Code , with a completely understandable error message.
Eric Elliot also describes an interesting approach to implementing increasing complexity:
Start with the simplest implementation, and move to more complex implementations only as required. When it comes to objects, that progression looks a bit like this:
― Eric Elliot ― Functional Mixins
Thought to use a series of simple and consistent examples to demonstrate this guidance. For familiarity sake, all the examples involve a calculation of a line:
Let use recreate those examples in TypeScript ; exploring any challenges we encounter:Pure Function
The simplest way to deliver reusable code is through a pure function.
A pure function is a function where the return value is only determined by its input values, without observable side effects. Some common things to avoid:Do not mutate the input, e.g., Array.prototype.push() . Do not use (changeable) variables outside of the function’s scope.
We can use an object literal to deliver the same reusable code, but adding the capability of changing the slope and intercept. It is important to note that there is only one object (a singleton).
One interesting thing that I learned while writing this article is that with TypeScript , this is typed as any ; explaining why we need to explicitly provide the return type.Factory
We might want to have more than one such object; each with its own slope and intercept.
The additional complexity of function mixins allow you to create objects that derive functionality from multiple sources. In this example, we have two objects ( objectA and objectB ) that are enhanced with the functionality from myFunctionalMixin .
This is the most complicated example to convert to TypeScript as we need to use Generics . At the same time, the changes only amount to creating the MyMixedObject interface and supplying parameter and return types on several functions.Class Much lik