// #-------------- This workstypeRepeat=(n: number)=>(s: string)=>string;exportconstrepeat: Repeat=n=>s=>s.repeat(n);// Sweet! s and n are both inferred!// -------------------------#// #----- Problems begin heretypeRepeat2=(n: number)=><Textends{repeat(n: number): T}>(repeatable: T)=>T;// Only n is inferred as number. Won't work with noImplicitAny enabledexportconstrepeat2Broken: Repeat2=n=>r=>r.repeat(n);// Workaround is to redeclare everything from the type signatureexportconstrepeat2Ugly: Repeat2=n=><Textends{repeat(n: number): T}>(r: T)=>r.repeat(n);// -------------------------#// #----------- It gets worse// Type inference breaks for all args following the generic one, so even if you use// the workaround, the next args won't regain inferencetypeRepeat3=(n: number)=><Textends{repeat(n: number): T}>(repeatable: T)=>(reverse: boolean)=>T;// Even if you explicitly provide the boilerplate for the generic arg, the boolean arg // won't be inferred. So the following won't work with noImplicitAny enabledexportconstrepeat3UglyAndBroken: Repeat3=n=><Textends{repeat(n: number): T}>(r: T)=>b=>{ ... }// You have to add typing for the last argexportconstrepeat3Uglier: Repeat3=n=><Textends{repeat(n: number): T}>(r: T)=>(b: boolean)=>{ ... }// -------------------------#I'd really appreciate better support for good inference in this kind of scenario, whether it is solved by supporting partial generic application or addition of participation of return-types in inference or whatever.
JS libraries that use a functional programming paradigm often end up loosely or any-ly typed, because you find yourself fighting the type system and adding repetitive type noise all over your code to derive any safety. A couple of examples where better support for FP would be useful:
- Libraries like React or Apollo make use of curried higher-order functions for solving cross-cutting concerns. In-fact, my original use case comes from React higher-order components
- Popular FP libraries like Ramda become tedious to use in a
noImplicitAny project because any generic functions passed or received from the library tend to quickly devolve into {} unless you repeatedly hand-hold the type system
Here is my original use-case, if interested:
exporttypeGetState<TState>=()=>TState;exporttypeSetState<TState>=(newState: TState)=>void;exporttypeStatelessComponent<TProp>=(prop: TProp)=>React.ReactElement<TProp>exporttypeStatefulComponent<TProp,TState>=(stateAccess: {getState: GetState<TState>,setState: SetState<TState>})=>StatelessComponent<TProp>;typeScrollableHOC=(options: ScrollableOptions)=><TextendsScrollableProps>(Child: ReactComponent<T>)=>StatefulComponent<T,ScrollableState>;// The introduction of the Child arg breaks type inference for getState, setState, propsconstscrollable: ScrollableHOC=opts=>Child=>({ getState, setState })=>props=>{// ...}
I'd really appreciate better support for good inference in this kind of scenario, whether it is solved by supporting partial generic application or addition of participation of return-types in inference or whatever.
JS libraries that use a functional programming paradigm often end up loosely or any-ly typed, because you find yourself fighting the type system and adding repetitive type noise all over your code to derive any safety. A couple of examples where better support for FP would be useful:
noImplicitAnyproject because any generic functions passed or received from the library tend to quickly devolve into{}unless you repeatedly hand-hold the type systemHere is my original use-case, if interested: