人心就是立国的大根本。——孙中山

问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*

Intro:

For some unknown reason most of our developers left
the company. We need to actively hire now.
In the media we've read that companies that invent
and publish new technologies attract more potential
candidates. We need to use this opportunity and
invent and publish some npm packages. Following the
new trend of functional programming in JS we
decided to develop a functional utility library.
This will put us on the bleading edge since we are
pretty much sure no one else did anything similar.
We also provided some jsdoc along with the
functions, but it might sometimes be inaccurate.

Exercise:

Provide proper typing for the specified functions.

Bonus:

Could you please also refactor the code to reduce
code duplication?
You might need some excessive type casting to make
it really short.

*/

/**
* 2 arguments passed: returns a new array
* which is a result of input being mapped using
* the specified mapper.
*
* 1 argument passed: returns a function which accepts
* an input and returns a new array which is a result
* of input being mapped using original mapper.
*
* 0 arguments passed: returns itself.
*
* @param {Function} mapper
* @param {Array} input
* @return {Array | Function}
*/
export function map(mapper, input) {
if (arguments.length === 0) {
return map;
}
if (arguments.length === 1) {
return function subFunction(subInput) {
if (arguments.length === 0) {
return subFunction;
}
return subInput.map(mapper);
};
}
return input.map(mapper);
}

/**
* 2 arguments passed: returns a new array
* which is a result of input being filtered using
* the specified filter function.
*
* 1 argument passed: returns a function which accepts
* an input and returns a new array which is a result
* of input being filtered using original filter
* function.
*
* 0 arguments passed: returns itself.
*
* @param {Function} filterer
* @param {Array} input
* @return {Array | Function}
*/
export function filter(filterer, input) {
if (arguments.length === 0) {
return filter;
}
if (arguments.length === 1) {
return function subFunction(subInput) {
if (arguments.length === 0) {
return subFunction;
}
return subInput.filter(filterer);
};
}
return input.filter(filterer);
}

/**
* 3 arguments passed: reduces input array it using the
* specified reducer and initial value and returns
* the result.
*
* 2 arguments passed: returns a function which accepts
* input array and reduces it using previously specified
* reducer and initial value and returns the result.
*
* 1 argument passed: returns a function which:
* * when 2 arguments is passed to the subfunction, it
* reduces the input array using specified initial
* value and previously specified reducer and returns
* the result.
* * when 1 argument is passed to the subfunction, it
* returns a function which expects the input array
* and reduces the specified input array using
* previously specified reducer and inital value.
* * when 0 argument is passed to the subfunction, it
* returns itself.
*
* 0 arguments passed: returns itself.
*
* @param {Function} reducer
* @param {*} initialValue
* @param {Array} input
* @return {* | Function}
*/
export function reduce(reducer, initialValue, input) {
if (arguments.length === 0) {
return reduce;
}
if (arguments.length === 1) {
return function subFunction(subInitialValue, subInput) {
if (arguments.length === 0) {
return subFunction;
}
if (arguments.length === 1) {
return function subSubFunction(subSubInput) {
if (arguments.length === 0) {
return subSubFunction;
}
return subSubInput.reduce(reducer, subInitialValue);
};
}
return subInput.reduce(reducer,subInitialValue);
}
}
if (arguments.length === 2) {
return function subFunction(subInput) {
if (arguments.length === 0) {
return subFunction;
}
return subInput.reduce(reducer, initialValue);
};
}
return input.reduce(reducer, initialValue);
}

/**
* 2 arguments passed: returns sum of a and b.
*
* 1 argument passed: returns a function which expects
* b and returns sum of a and b.
*
* 0 arguments passed: returns itself.
*
* @param {Number} a
* @param {Number} b
* @return {Number | Function}
*/
export function add(a, b) {
if (arguments.length === 0) {
return add;
}
if (arguments.length === 1) {
return function subFunction(subB) {
if (arguments.length === 0) {
return subFunction;
}
return a + subB;
};
}
return a + b;
}

/**
* 2 arguments passed: subtracts b from a and
* returns the result.
*
* 1 argument passed: returns a function which expects
* b and subtracts b from a and returns the result.
*
* 0 arguments passed: returns itself.
*
* @param {Number} a
* @param {Number} b
* @return {Number | Function}
*/
export function subtract(a, b) {
if (arguments.length === 0) {
return subtract;
}
if (arguments.length === 1) {
return function subFunction(subB) {
if (arguments.length === 0) {
return subFunction;
}
return a - subB;
};
}
return a - b;
}

/**
* 2 arguments passed: returns value of property
* propName of the specified object.
*
* 1 argument passed: returns a function which expects
* propName and returns value of property propName
* of the specified object.
*
* 0 arguments passed: returns itself.
*
* @param {Object} obj
* @param {String} propName
* @return {* | Function}
*/
export function prop(obj, propName) {
if (arguments.length === 0) {
return prop;
}
if (arguments.length === 1) {
return function subFunction(subPropName) {
if (arguments.length === 0) {
return subFunction;
}
return obj[subPropName];
};
}
return obj[propName];
}

/**
* >0 arguments passed: expects each argument to be
* a function. Returns a function which accepts the
* same arguments as the first function. Passes these
* arguments to the first function, the result of
* the first function passes to the second function,
* the result of the second function to the third
* function... and so on. Returns the result of the
* last function execution.
*
* 0 arguments passed: returns itself.
*
* TODO TypeScript
* * Should properly handle at least 5 arguments.
* * Should also make sure argument of the next
* function matches the return type of the previous
* function.
*
* @param {Function[]} functions
* @return {*}
*/
export function pipe(...functions) {
if (arguments.length === 0) {
return pipe;
}
return function subFunction() {
let nextArguments = Array.from(arguments);
let result;
for (const func of functions) {
result = func(...nextArguments);
nextArguments = [result];
}
return result;
};
}

报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
index.ts(46,21): error TS7006: Parameter 'mapper' implicitly has an 'any' type.
index.ts(46,29): error TS7006: Parameter 'input' implicitly has an 'any' type.
index.ts(51,37): error TS7006: Parameter 'subInput' implicitly has an 'any' type.
index.ts(77,24): error TS7006: Parameter 'filterer' implicitly has an 'any' type.
index.ts(77,34): error TS7006: Parameter 'input' implicitly has an 'any' type.
index.ts(82,37): error TS7006: Parameter 'subInput' implicitly has an 'any' type.
index.ts(120,24): error TS7006: Parameter 'reducer' implicitly has an 'any' type.
index.ts(120,33): error TS7006: Parameter 'initialValue' implicitly has an 'any' type.
index.ts(120,47): error TS7006: Parameter 'input' implicitly has an 'any' type.
index.ts(125,37): error TS7006: Parameter 'subInitialValue' implicitly has an 'any' type.
index.ts(125,54): error TS7006: Parameter 'subInput' implicitly has an 'any' type.
index.ts(130,48): error TS7006: Parameter 'subSubInput' implicitly has an 'any' type.
index.ts(141,37): error TS7006: Parameter 'subInput' implicitly has an 'any' type.
index.ts(163,21): error TS7006: Parameter 'a' implicitly has an 'any' type.
index.ts(163,24): error TS7006: Parameter 'b' implicitly has an 'any' type.
index.ts(168,37): error TS7006: Parameter 'subB' implicitly has an 'any' type.
index.ts(191,26): error TS7006: Parameter 'a' implicitly has an 'any' type.
index.ts(191,29): error TS7006: Parameter 'b' implicitly has an 'any' type.
index.ts(196,37): error TS7006: Parameter 'subB' implicitly has an 'any' type.
index.ts(220,22): error TS7006: Parameter 'obj' implicitly has an 'any' type.
index.ts(220,27): error TS7006: Parameter 'propName' implicitly has an 'any' type.
index.ts(225,37): error TS7006: Parameter 'subPropName' implicitly has an 'any' type.
index.ts(256,17): error TS7023: 'pipe' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
index.ts(256,22): error TS7019: Rest parameter 'functions' implicitly has an 'any[]' type.
test.ts(4,20): error TS2554: Expected 2 arguments, but got 0.
test.ts(5,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(8,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(10,23): error TS2554: Expected 3 arguments, but got 0.
test.ts(11,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(14,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(17,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(20,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(22,23): error TS2554: Expected 2 arguments, but got 0.
test.ts(23,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(26,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(28,20): error TS2554: Expected 2 arguments, but got 0.
test.ts(29,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(32,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(34,25): error TS2554: Expected 2 arguments, but got 0.
test.ts(35,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(38,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(40,21): error TS2554: Expected 2 arguments, but got 0.
test.ts(41,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(44,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(46,26): error TS2554: Expected 2 arguments, but got 1.
test.ts(46,43): error TS2554: Expected 2 arguments, but got 1.
test.ts(46,56): error TS2554: Expected 3 arguments, but got 2.
test.ts(47,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.
test.ts(49,30): error TS2554: Expected 2 arguments, but got 1.
test.ts(49,47): error TS2554: Expected 2 arguments, but got 1.
test.ts(50,12): error TS2344: Type 'false' does not satisfy the constraint 'true'.

答案:

1