Skip to content

Commit fc324c6

Browse files
christopherthielenmergify[bot]
authored andcommitted
fix(hof): Rewrite curry from scratch
Fixes #350
1 parent 351b38d commit fc324c6

File tree

2 files changed

+66
-12
lines changed

2 files changed

+66
-12
lines changed

src/common/hof.ts

+7-12
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,17 @@ import { Predicate } from './common';
4545
*
4646
* ```
4747
*
48-
* Stolen from: http://stackoverflow.com/questions/4394747/javascript-curry-function
49-
*
5048
* @param fn
5149
* @returns {*|function(): (*|any)}
5250
*/
5351
export function curry(fn: Function): Function {
54-
const initial_args = [].slice.apply(arguments, [1]);
55-
const func_args_length = fn.length;
56-
57-
function curried(args: any[]) {
58-
if (args.length >= func_args_length) return fn.apply(null, args);
59-
return function() {
60-
return curried(args.concat([].slice.apply(arguments)));
61-
};
62-
}
63-
return curried(initial_args);
52+
return function curried() {
53+
if (arguments.length >= fn.length) {
54+
return fn.apply(this, arguments);
55+
}
56+
const args = Array.prototype.slice.call(arguments);
57+
return curried.bind(this, ...args);
58+
};
6459
}
6560

6661
/**

test/hofSpec.ts

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { curry } from '../src/common';
2+
3+
describe('curry', () => {
4+
let original: jasmine.Spy;
5+
beforeEach(() => {
6+
original = jasmine.createSpy('original', function(a, b, c) {});
7+
});
8+
9+
it('should accept a function and return a new function', () => {
10+
expect(typeof curry(original)).toBe('function');
11+
});
12+
13+
it('should return a function that invokes original only when all arguments are supplied', () => {
14+
const curried1 = curry(original);
15+
curried1(1, 2, 3);
16+
expect(original).toHaveBeenCalledTimes(1);
17+
expect(original).toHaveBeenCalledWith(1, 2, 3);
18+
});
19+
20+
it('should pass extra arguments through to original function', () => {
21+
const curried1 = curry(original);
22+
curried1(1, 2, 3, 4);
23+
expect(original).toHaveBeenCalledTimes(1);
24+
expect(original).toHaveBeenCalledWith(1, 2, 3, 4);
25+
});
26+
27+
it('should keep returning functions that return functions if no arguments are supplied', () => {
28+
const curried1 = curry(original);
29+
expect(typeof curried1).toBe('function');
30+
31+
const curried2 = curried1();
32+
expect(typeof curried2).toBe('function');
33+
34+
const curried3 = curried2();
35+
expect(typeof curried3).toBe('function');
36+
37+
const curried4 = curried3();
38+
expect(typeof curried4).toBe('function');
39+
40+
const curried5 = curried4();
41+
expect(typeof curried5).toBe('function');
42+
43+
const curried6 = curried5();
44+
expect(typeof curried6).toBe('function');
45+
46+
expect(original).toHaveBeenCalledTimes(0);
47+
});
48+
49+
it('should keep returning functions that return functions until all arguments are supplied', () => {
50+
const curried1 = curry(original);
51+
const curried2 = curried1(1);
52+
const curried3 = curried2(2);
53+
const result = curried3(3);
54+
55+
expect(result).toBeUndefined();
56+
expect(original).toHaveBeenCalledTimes(1);
57+
expect(original).toHaveBeenCalledWith(1, 2, 3);
58+
});
59+
});

0 commit comments

Comments
 (0)