javascript - Typescript funkcia tapAsync nedokáže nastaviť správne typy
Chcem byť schopný zostaviť niekoľko ES6 asynchrónnych funkcií pomocou TypeScriptu. Funkcia tap by mala vrátiť argument, ak z tapovanej funkcie nič nie je vrátené, ale tapovať vrátenú hodnotu, ak niečo je vrátené z tapovanej funkcie.
príklad TypeScript ihriska
Dokážem to rozbehnúť bez písania typov, ale mám problémy s nastavovaním typov. Pozrite si ukážku pre príklad kódu fungujúceho v Javascript.
Funkcia tapovaná sa jednoducho volá s hodnotou x x => fn(x), potom sa reťazí, aby vrátila buď návratovú hodnotu y alebo tapovanú hodnotu x x => fn(x).then(y => y || x)
Táto prvá verzia používajúca typ any funguje, ale dostávam chyby, keď sa špecifikujem na spracovanie typov vo funkciách, ktoré sú tapped.
const tapAsync = (fn: (x: any) => Promise<any>) => (
x: any
): Promise<any> => fn(x).then((y: any) => y || x)
Aby som bol konkrétnejší, používam dve generiká, X pre počiatočný argument a Y pre navrátenú hodnotu odchytenej funkcie.
const tapAsync = (fn: <X>(x: X) => Promise<X>) => (
x: X
): Promise<Y|X> => fn(x).then(<Y>(y: Y) => y || x)
Keď volám funkcie pomocou tapAsync, dostanem nasledujúcu chybu.
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))
V Typescripte nenastavujem žiadne typy na tapnutých funkciách, ale skúšal som použiť generické typy na druhej funkcii dva, ale ani to nefunguje
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))Ďakujem za akúkoľvek pomoc!
============== úprava 2020-09-01 ====================
Hrám sa s kódom a trochu som rozpracoval typy, ale teraz dostávam chybu pri funkcii two, keď vracia nový objekt, aj keď má rovnaký tvar.
nový príklad prostredia TypeScript
const tapAsync = <X, Y>(fn: (x: X) => Promise<Y|void>) =>
(x: X): Promise<X|Y> =>
fn(x).then((y: Y|void) => y || x)
Odpoveď č. 1
Myslím, že s preťažením to funguje. A odvodzovanie typov vyzerá správne. V podstate to umožňuje kompilátoru TypeScriptu odvodiť, že nikdy neexistuje návrat typu (x:X)=>Promise<void | Y>. K tomu došlo preto, že po prvom volaní asynchrónnej funkcie, ktorá nič nevracia function :Promise<void>, bol typ Y odvodzený ako tento typ, a tak by Promise.then(... v ďalšom volaní pokúsil použiť X ako void | Args, čo by viedlo k (x: void | Args)=>...., čo je nekompatibilné s očakávaným (x: Args)=>....
Skontrolujte toto ihrisko váš príklad s preťažením
function tapAsync <X,Y>(fn: (x:X)=>Promise<void>): (x:X)=>Promise<X>;
function tapAsync <X,Y>(fn: (x:X)=>Promise<Y>): (x:X)=>Promise<Y>;
function tapAsync <X, Y>(fn: (x: X) => Promise<Y|void>) {
return (x: X) => fn(x).then(y => y||x )
}
Upraviť: Pri opätovnom čítaní mojej odpovede som zabudol spomenúť, že problém spôsobuje (y: void| Y )=> Y||X, ktorý nedokáže odvodiť, že nikdy nemôže vrátiť void, ak pôvodné X nebolo void.
