I want to be able to tap a few ES6 async functions together using typescript. The tap function should return the argument if nothing is returned from the tapped function, but tap the returned value if anything is returned from a tapped function.
I can get it to work without typeing, but having issues setting the types. Please see the snippet for an example of the code working in Javascript.
The tapped function is simply called with the x value x => fn(x), then chained to return either the return value y or the tapped value x x => fn(x).then(y => y || x)
This first version using the any type works, but I'm getting errors when getting specific on handling the types in the tapped functions.
const tapAsync = (fn: (x: any) => Promise<any>) => (
x: any
): Promise<any> => fn(x).then((y: any) => y || x)
To get more specific I'm using Two generics, X for the initial argument, and Y for the retured value of the tapped function.
const tapAsync = (fn: <X>(x: X) => Promise<X>) => (
x: X
): Promise<Y|X> => fn(x).then(<Y>(y: Y) => y || x)
When I call the functions using tapAsync I get the following error.
src/index.ts:45:18 - error TS2345: Argument of type '({ foo }: { foo: any; }) => Promise<void>' is not assignable to parameter of type '<X>(x: X) => Promise<X>'.
Types of parameters '__0' and 'x' are incompatible.
Type 'X' is not assignable to type '{ foo: any; }'.
45 .then(tapAsync(one))
~~~
src/index.ts:46:18 - error TS2345: Argument of type '({ foo }: { foo: any; }) => Promise<{ foo: any; bar: string; }>' is not assignable to parameter of type '<X>(x: X) => Promise<X>'.
Types of parameters '__0' and 'x' are incompatible.
Type 'X' is not assignable to type '{ foo: any; }'.
46 .then(tapAsync(two))
~~~
src/index.ts:47:18 - error TS2345: Argument of type '({ foo, bar }: { foo: any; bar: any; }) => Promise<void>' is not assignable to parameter of type '<X>(x: X) => Promise<X>'.
Types of parameters '__0' and 'x' are incompatible.
Type 'X' is not assignable to type '{ foo: any; bar: any; }'.
47 .then(tapAsync(three))
I'm not setting any types in typescript on the tapped functions, but I have tried using generic types on the second function two but that also doesn't work
async function two<X>({ foo }): Promise<X> {
console.log('two', foo)
return {
foo,
bar: 'bar'
}
}
async function one({ foo }) {
console.log('one', foo)
}
async function two({ foo }) {
console.log('two', foo)
return {
foo,
bar: 'bar'
}
}
async function three({ foo, bar }) {
console.log('three', foo, bar)
}
const tapAsync = fn => x => fn(x).then(y => y || x)
Promise.resolve({ foo: 'foo' })
.then(tapAsync(one))
.then(tapAsync(two))
.then(tapAsync(three))
Thanks for any help!
============== edit 2020-09-01 ====================
I have been playing with the code and have fleshed out the types a little more, but now I get an error on the two function when it returns a new object even though it is the same shape.
new typescript playground example
const tapAsync = <X, Y>(fn: (x: X) => Promise<Y|void>) =>
(x: X): Promise<X|Y> =>
fn(x).then((y: Y|void) => y || x)