Typescript-typningar för generiska curry-funktioner
Jag försöker bli bättre på FP men har svårt att hantera typning av generiska "curry"-funktioner.
Till exempel har jag skrivit en "Curry"-version av reduce:
const reduce = <S, R>(fn: (result: R, obj: S, i?: number, arr?: S[]) => R, init: R) =>
(objects: S[]) =>
objects.reduce(fn, init);
const numToSum: number[] = [1,2,3,5,8,13];
const result = reduce((sum, n) => sum + n, 0)(numToSum);
Problemet är att TypeScript uppenbarligen inte kan veta typen av S förrän du faktiskt anropar curry-funktionen med numToSum.
Det är mer uppenbart när du ser det utan curry-samtalet:
const sumNumbersFn = reduce((sum, n) => sum + n, 0);
I det här fallet kan du åtgärda detta genom att skriva typen på funktionens argument själv med n: number eller genom att uttryckligen ange de generiska parametrarna <number[], number>.
Det förstnämnda verkar rimligt, men det jag stöter på är att ju mer saker blir komplexa, desto mer måste jag ständigt ange generisk signatur.
Jag undrar om jag missar något, och om det faktiskt är möjligt att få TypeScript att ">sluta" typen från de senare funktionsanropen?
Tillbaka till det första exemplet:
const result = reduce((sum, n) => sum + n, 0)(numToSum);
Det verkar som att kompilatorn faktiskt BORDE ha all information som behövs för att härleda typer.
Kanske är mina typer bara fel?
Uppdatera
Här är ett mer konkret/fullständigt exempel på problemet jag stöter på
TS-Lekplats
Svar #1
Allt du behöver göra är att deklarera en funktion som du returnerar från select-funktionen som generisk:
function select<T, S>(sFn: (obj: T) => S) {
function computation<G>(fn: (obj: S) => G) {
return (obj: T) => fn(sFn(obj));
}
return computation;
}
P.S: Jag vet inte varför sådan typ av syntax inte fungerar i TS playground:
const select = <T, S>(sFn: (obj: T) => S) => <G>(fn: (obj: S) => G) => {
return (obj: T) => fn(sFn(obj));
}
Kanske på grund av några TS-konfigurationsinställningar. Därför skrev jag lösningen som en funktionsdeklaration istället för ett funktionsuttryck.
