I have defined a function in JS that keep taking functions(params => string) until it receive an object then it resolves the final string as a concatenation of functions invocations over the same object that is passed at the end
Here is the function
export function prefixer(func1?: any) {
function identity(x: any) { return x; }
function curriedPrefixer(fns: any[]) {
return function next(param: any) {
if (typeof param == 'function') {
return curriedPrefixer(
fns.concat(param)
);
}
if (typeof param == 'object')
return fns.reduce(
(prev, next) => prev + next(param), ''
);
return undefined;
}
}
return curriedPrefixer([func1 || identity])
}
My problem is in defining the right types for its params and return type so the user of this function can pass a generic type(to help the function know what is the type of the final params object) and can help the user re-invoke the output of that function over and over.
Here's the function in a test case:
test('should auto prefix', () => {
let prefix1: any = prefixer((params: any) => `https://wwww.${params.domain}.com`)
let prefix2: any = prefix1(() => '/path/to/item')
let prefix3: any = prefix2((params: any) => `/${params.itemId}`)
let params = {
domain: 'google',
itemId: '5444'
}
let resolvedString1 = prefix1(params);
let resolvedString2 = prefix2(params);
let resolvedString3 = prefix3(params);
let trueResult1 = `https://wwww.${params.domain}.com`
let trueResult2 = `https://wwww.${params.domain}.com/path/to/item`
let trueResult3 = `https://wwww.${params.domain}.com/path/to/item/${params.itemId}`
expect(resolvedString1).toEqual(trueResult1);
expect(resolvedString2).toEqual(trueResult2);
expect(resolvedString3).toEqual(trueResult3);
});
I've tried some nonsense ideas but didn't get any close and didn't find a helping answer regarding recursive functions in typescript.
Here's something I've tried but doesn't solve the types definition
export function prefixer<T>(func1?: any) {
function identity(x: any) { return x; }
function curriedPrefixer<M>(fns: any[]) {
return function next<S>(param: S | M | ((p: S | M) => any)) {
if (typeof param == 'function') {
return curriedPrefixer(
fns.concat(param)
);
}
if (typeof param == 'object')
return fns.reduce(
(prev, next) => prev + next(param), ''
);
return undefined;
}
}
return curriedPrefixer<T>([func1 || identity])
}
// I still have to pass (p: any)...
let prefix1 = prefixer<{ domain: string }>((p: any) => `https://wwww.${p.domain}.com`)
let prefix2 = prefix1<{ itemId: string }>((p: any) => `https://wwww.${p.itemId}.com`)