# Writing Flowtype annotations for Ramda: Add and Subtract, Continued

### Specifying the exact number of arguments

At the end of the last post, this is how we had defined *add* and *subtract*:

declare type NumericFn2 =

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

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

declare var subtract: NumericFn2;

declare var add: NumericFn2;

We had some simple tests that seemed to pass:

add(1);

add(1)(1);

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

But if we try this:

subtract(1, 'a'); // no error

we don’t get an error! What might be going on? Check this out:

subtract(1, 'a')(1) == 1; // no errors

subtract(1, 'a')(1); // error: number cannot be compared to string

So it seems that *subtract(1, ‘a’)* is assumed to match the same case as *subtract(1)*, since where the *‘a’* is just assumed to be a superfluous extra argument.

Thus, we need to encode that *subtract(1, ‘a’)* is not a valid usage by making it explicit that the unary add only takes one argument.

This doc describes the trick for declaring a function with a fixed number of argument. And here is how fix *NumericFn2*:

declare type NumericFn2 =

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

& ((x: number, ...rest: Array<void>) => ((y: number) => number));

declare var subtract: NumericFn2;

declare var add: NumericFn2;

Now this once valid expression:

subtract(1, 'a')(1);

Results in a several Flow warnings explaining why neither type in the intersection will work with it:

If we wanted to, we could do the same trick for the 2-ary version of add, even though something like *add(1, 2, 3, 4, 5)* is harmless. Having Flow detect something like this would eliminate a code smell, so there might be some value in doing it:

declare type NumericFn1 = (x: number, ...rest: Array<void>) => number;

declare type NumericFn2 =

& ((x: number, y: number, ...rest: Array<void>) => number)

& ((x: number, ...rest: Array<void>) => NumericFn1);

Here, I aliased *NumericFn1* to the unary function for conciseness. We could actually use this type for *R.inc* and *R.dec*.

#### Using interfaces

In the TypeScript definitions for Ramda, curried functions are actually defined using an interface:

// https://github.com/donnut/typescript-ramda/blob/master/ramda.d.ts#L75

interface CurriedFunction2<T1, T2, R> {

(t1: T1): (t2: T2) => R;

(t1: T1, t2: T2): R;

}

Here, this definition uses polymorphism, in letting types *T1*, etc. be variables, while we are using the concrete type *number*.

The more familiar use case for interfaces comes from OOP, where you might want a class to extend an interface, thus forcing it to have a common API with other classes that extend it.

Even in a language like Scala, a callable object *Foo* would need to define a method *apply*, whereby *Foo(x)* is the same as *Foo.apply(x)*. So the syntax here is kind of unusual to me.

But it turns out that Flow actually supports this too, although this use case is not documented. So if we wanted to, we could do this:

declare type NumericFn1 = (x: number, ...rest: Array<void>) => number;

declare interface NumericFn2 {

(x: number, y: number, ...rest: Array<void>): number;

(x: number, ...rest: Array<void>): NumericFn1;

}

which is really interesting to me. From what I can gather, the errors caused by *subtract(1, ‘a’)* look the same as when we used an intersection type, but because this is not documented, who knows if this technique is seen as a “good idea” or whether it will continue to be supported.

#### Next time

Believe or not, we are still not quite done with simple math functions in Ramda! In the next post, I will cover polymorphism and show how it can be used to lay the foundation for non-math functions.

We will also tackle the interesting function *and* whose type signature is *any *→* any *→* any* (but not really!) and see how we can safely type such a crazy function.