Hello I am learning typescript and i follow this exercises: Link
I have problem understanding how should i proced with this example.
there is a code like this:
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);
}
and I am supposed to add types to this. I managed to create something like this:
export function map<T>(mapper: Function, input : T[]| any) : T[] | Function {
if (arguments.length === 0) {
return map;
}
if (arguments.length === 1) {
return function subFunction(subInput: T[]|any): T[] | Function {
if (arguments.length === 0) {
return subFunction;
}
return subInput.map(mapper);
};
}
return input.map(mapper);
}
typescript do not returns compilation errors now but i still fail the test. I do not understand what it is expected from me to make this work.
I can check suggested answer but whe i look at it this is dark magic for me.
I could check test.ts for what is expected but notation like const mapResult1 = map()(String)()([1, 2, 3]); is looking very strange for me.
Well it's just some use case of the map function:
map() the result is map itselfmap(String) which returns subFunctionsubFunction() which returns subFunction itselfsubFunction([1, 2, 3]) which returns the result of the expression [1, 2, 3].map(String): ['1', '2', '3']The type of this result is a string[] because every element of the final array is the result of String being called as a function is always a string. Your typings are supposed to resolve this type without even executing the code.
Here is one possible solution found in the source code of the exercises you are doing. They actually revamped the implementation to make it "functional" (return a new function for every unresolved parameter)
function toFunctional<T extends Function>(func: T): Function {
const fullArgCount = func.length;
function createSubFunction(curriedArgs: unknown[]) {
return function(this: unknown) {
const newCurriedArguments = curriedArgs.concat(Array.from(arguments));
if (newCurriedArguments.length > fullArgCount) {
throw new Error('Too many arguments');
}
if (newCurriedArguments.length === fullArgCount) {
return func.apply(this, newCurriedArguments);
}
return createSubFunction(newCurriedArguments);
};
}
return createSubFunction([]);
}
interface MapperFunc<I, O> {
(): MapperFunc<I, O>;
(input: I[]): O[];
}
interface MapFunc {
(): MapFunc;
<I, O>(mapper: (item: I) => O): MapperFunc<I, O>;
<I, O>(mapper: (item: I) => O, input: I[]): O[];
}
/**
* 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.
*/
export const map = toFunctional(<I, O>(fn: (arg: I) => O, input: I[]) => input.map(fn)) as MapFunc;
Here is a simple solution:
interface SubFunction<I, O> {
(): SubFunction<I, O>;
(input: I[]): O[];
}
function map<I, O>(): typeof map;
function map<I, O>(mapper: (i: I) => O): SubFunction<I, O>;
function map<I, O>(mapper: (i: I) => O, input: I[]): O[];
function map<I, O>(mapper?: (i: I) => O, input?: I[]) {
if (mapper && input) {
return input.map(mapper);
}
if (mapper) {
const subFunction = (input?: I[]) => input ? input.map(mapper) : subFunction;
return subFunction;
}
return map;
}
const mapResult1 = map()(String)()([1, 2, 3]);
function apart from top-level, no arguments)Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With