# Writing Flowtype annotations for Ramda: Add and Subtract

### Function types

Ramda provides simple mathematical functions like add and subtract, which do what you might expect, but are (like all functions in Ramda) *curried*:

// number -> number -> number

add

// number

const two = add(1, 1);

// number -> number

const addOne = add(1);

// number

const three = addOne(2);

This means, in JavaScript, these functions are *overloaded*, since function calls with different numbers of arguments have different return values.

Thus, *add* needs two function declarations to account for both kinds of calls:

// types.js

declare function add(x: number, y: number): number;

declare function add(x: number) : (y: number) => number;

// test.js

add(1);

add(1)(1);

add('a'); // error

add(1)(1) == 'a' // error

The second declaration uses Flow’s syntax for typing anonymous functions, which sort of looks like ES2015 arrow function syntax. *(y: a) => b* is the type for a function which takes one argument of type *a*, and returns a value of type *b*. In Haskell syntax, this is the same as *a -> b*. The argument name *y* can be anything; it doesn’t need to match the name in the implementation.

#### DRYing up with function types

*add* and *subtract* have the same type, so while this works:

declare function add(x: number, y: number): number;

declare function add(x: number): (y: number) => number;

declare function subtract(x: number, y: number): number;

declare function subtract(x: number): (y: number) => number;

we can express the sameness of these functions by combining them into a single type:

// note: the leading `&`s are a stylistic choice

declare type NumericFn2 =

& ((x: number, y: number) => number)

& ((x: number) => ((y: number) => number))

declare var add: NumericFn2;

declare var subtract: NumericFn2;

This defines add and subtract as an *intersection type*, meaning that these functions simultaneously satisfy both types in that expression.

#### Digression: Why not a union type?

Based on how *add* is used, it might seem more sensible to model it as a *union type*: as either a 2-ary or unary function. Personally, I am tempted towards this interpretation, since union in set theory is analogous to disjunction in logic. This , however, is actually somewhat misleading. Hence, this digression to try and clear things up.

Suppose we were to model *NumericFn2* as a union type, like so:

declare type NumericFn2 =

| ((x: number, y: number) => number)

| ((x: number) => ((y: number) => number))

then you will see this error:

add(1)

^^^^^^ undefined (too few arguments, expected default/rest parameters). This type is incompatible with

6: | ((x: number, y: number) => number)

^^^^^^ number. See lib: flow-typed/types.js:6

It turns out that when you give a value a union type, then you are assuming that the value will be compatible with *every* possibility encoded in that type, especially if you are not doing any dynamic tests in your code to “refine” the value’s type.

The expression *add(1)* is incompatible with the first type in the union, because *y* is a required variable. But even if we were to make that an optional variable:

declare type NumericFn2 =

| ((x: number, y?: number) => number)

| ((x: number) => ((y: number) => number))

This is not only incorrect based on how *add* actually works, but now this is a problem:

add(1)(1)

// error: Function cannot be called on number

The first 2-ary function type is still problematic, but this time because the return value is assumed to be a number.

So basically, while union types are easier to tag variables with (since they are more generous), such variables are harder to actually do anything with. Without refinement or dynamic type checks, there are fewer guarantees on what you can do with them. For example, consider this code:

type Flexible = string | number;

function foo(x: Flexible) {

const withBang = x + "!"; // okay, since `+` works with both

const times2 = x * 2; // not okay, since you can't multiply strings

}

If we were to make *Flexible* even more flexible as *string | number | Object*, then nothing in the function would type check.

On the other hand, while intersection types are more restrictive, this also means there are more things you can safely do with it.

#### Next time

Amazingly, we are not quite done with *add* and *subtract*, even though we have already covered a lot of concepts. In the next post, I will try to stress test these declarations to make sure that they are as safe and useful as they can be. I will also introduce other techniques for DRYing up these types.