diff --git a/curry-right/docs/types/index.d.ts b/curry-right/docs/types/index.d.ts index a9f71aa9..a4e85eff 100644 --- a/curry-right/docs/types/index.d.ts +++ b/curry-right/docs/types/index.d.ts @@ -18,13 +18,32 @@ // TypeScript Version: 4.1 +/** +* Utility type to reverse a tuple type. +*/ +type ReverseTuple> = T extends [infer First, ...infer Rest] ? [...ReverseTuple, First] : []; // eslint-disable-line @typescript-eslint/no-explicit-any + +/** + * Curry function type for curryRight. + */ +type CurryRightFunction< + TThis, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +> = ( this: TThis, ...args: TArgs ) => TReturn; + /** * Curry function. * * @param v - curried function parameter * @returns partially applied curry function or curried function result */ -type Closure = ( v: any ) => any; +type Closure< + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +> = ReverseTuple extends [infer TFirst, ...infer TRest] + ? ( v: TFirst ) => Closure, TReturn> + : TReturn; /** * Transforms a function into a sequence of functions each accepting a single argument. @@ -50,7 +69,15 @@ type Closure = ( v: any ) => any; * var sum = f( 2 )( 3 ); * // returns 5 */ -declare function curryRight( fcn: Function, arity: number, thisArg?: any ): Closure; +declare function curryRight< + TThis extends object, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +>( + fcn: CurryRightFunction, + arity: number, + thisArg?: TThis +): Closure; /** * Transforms a function into a sequence of functions each accepting a single argument. @@ -74,7 +101,14 @@ declare function curryRight( fcn: Function, arity: number, thisArg?: any ): Clos * var sum = f( 2 )( 3 ); * // returns 5 */ -declare function curryRight( fcn: Function, thisArg?: any ): Closure; +declare function curryRight< + TThis extends object, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +>( + fcn: CurryRightFunction, + thisArg?: TThis +): Closure; // EXPORTS // diff --git a/curry-right/docs/types/test.ts b/curry-right/docs/types/test.ts index a3b29c42..4577cdbf 100644 --- a/curry-right/docs/types/test.ts +++ b/curry-right/docs/types/test.ts @@ -23,9 +23,23 @@ import curryRight = require( './index' ); // The function returns a function... { - curryRight( ( x: number, y: number ): number => x + y ); // $ExpectType Closure - curryRight( ( x: number, y: number ): number => x + y, 2 ); // $ExpectType Closure - curryRight( ( x: number, y: number ): number => x + y, 2, {} ); // $ExpectType Closure + curryRight( ( x: number, y: number ): number => x + y ); // $ExpectType (v: number) => (v: number) => number + curryRight( ( x: number, y: number ): number => x + y, 2 ); // $ExpectType (v: number) => (v: number) => number + curryRight( ( x: number, y: number ): number => x + y, 2, {} ); // $ExpectType (v: number) => (v: number) => number + curryRight( ( x: string, y: string ): string => x + y, {} ); // $ExpectType (v: string) => (v: string) => string + curryRight( ( x: string, y: string ): string => x + y, 2, {} ); // $ExpectType (v: string) => (v: string) => string + curryRight( ( str: string, n: number ): string => str.substring( n ) ); // $ExpectType (v: number) => (v: string) => string + + const cxt = { + 'count': 0, + 'multiply': function multiply( this: { count: number }, x: number, y: number ): number { + this.count += 1; // eslint-disable-line no-invalid-this + return x * y; + } + }; + curryRight( cxt.multiply ); // $ExpectType (v: number) => (v: number) => number + curryRight( cxt.multiply, 2 ); // $ExpectType (v: number) => (v: number) => number + curryRight( cxt.multiply, 2, { 'count': 2 } ); // $ExpectType (v: number) => (v: number) => number } // The compiler throws an error if the function is provided a first argument other than a function... @@ -38,6 +52,19 @@ import curryRight = require( './index' ); curryRight( 'abc' ); // $ExpectError } +// The compiler throws an error if the function is provided a this argument which does not constitute a valid `this` context... +{ + const cxt = { + 'count': 0, + 'multiply': function multiply( this: { count: number }, x: number, y: number ): number { + this.count += 1; // eslint-disable-line no-invalid-this + return x * y; + } + }; + curryRight( cxt.multiply, { 'COUNT': 2 } ); // $ExpectError + curryRight( cxt.multiply, 2, {} ); // $ExpectError +} + // The compiler throws an error if the function is provided more than three arguments... { curryRight( ( x: number, y: number ): number => x + y, 2, {}, 4 ); // $ExpectError diff --git a/curry/docs/types/index.d.ts b/curry/docs/types/index.d.ts index 2e8a7769..bb831fe7 100644 --- a/curry/docs/types/index.d.ts +++ b/curry/docs/types/index.d.ts @@ -18,13 +18,27 @@ // TypeScript Version: 4.1 +/** +* Curry function type. +*/ +type CurryFunction< + TThis, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +> = ( this: TThis, ...args: TArgs ) => TReturn; + /** * Curry function. * * @param v - curried function parameter * @returns partially applied curry function or curried function result */ -type Closure = ( v: any ) => any; +type Closure< + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +> = TArgs extends [infer TFirst, ...infer TRest] + ? ( v: TFirst ) => Closure + : TReturn; /** * Transforms a function into a sequence of functions each accepting a single argument. @@ -49,7 +63,15 @@ type Closure = ( v: any ) => any; * var sum = f( 2 )( 3 ); * // returns 5 */ -declare function curry( fcn: Function, arity: number, thisArg?: any ): Closure; +declare function curry< + TThis extends object, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +>( + fcn: CurryFunction, + arity: number, + thisArg?: TThis +): Closure; /** * Transforms a function into a sequence of functions each accepting a single argument. @@ -72,7 +94,14 @@ declare function curry( fcn: Function, arity: number, thisArg?: any ): Closure; * var sum = f( 2 )( 3 ); * // returns 5 */ -declare function curry( fcn: Function, thisArg?: any ): Closure; +declare function curry< + TThis extends object, + TArgs extends Array, // eslint-disable-line @typescript-eslint/no-explicit-any + TReturn +>( + fcn: CurryFunction, + thisArg?: TThis +): Closure; // EXPORTS // diff --git a/curry/docs/types/test.ts b/curry/docs/types/test.ts index 4f733c0f..c91d4b86 100644 --- a/curry/docs/types/test.ts +++ b/curry/docs/types/test.ts @@ -23,10 +23,22 @@ import curry = require( './index' ); // The function returns a function... { - curry( ( x: number, y: number ): number => x + y ); // $ExpectType Closure - curry( ( x: number, y: number ): number => x + y, 2 ); // $ExpectType Closure - curry( ( x: number, y: number ): number => x + y, {} ); // $ExpectType Closure - curry( ( x: number, y: number ): number => x + y, 2, {} ); // $ExpectType Closure + curry( ( x: number, y: number ): number => x + y ); // $ExpectType (v: number) => (v: number) => number + curry( ( x: number, y: number ): number => x + y, 2 ); // $ExpectType (v: number) => (v: number) => number + curry( ( x: string, y: string ): string => x + y, {} ); // $ExpectType (v: string) => (v: string) => string + curry( ( x: string, y: string ): string => x + y, 2, {} ); // $ExpectType (v: string) => (v: string) => string + curry( ( str: string, n: number ): string => str.substring( n ) ); // $ExpectType (v: string) => (v: number) => string + + const cxt = { + 'count': 0, + 'multiply': function multiply( this: { count: number }, x: number, y: number ): number { + this.count += 1; // eslint-disable-line no-invalid-this + return x * y; + } + }; + curry( cxt.multiply ); // $ExpectType (v: number) => (v: number) => number + curry( cxt.multiply, 2 ); // $ExpectType (v: number) => (v: number) => number + curry( cxt.multiply, 2, { 'count': 2 } ); // $ExpectType (v: number) => (v: number) => number } // The compiler throws an error if the function is provided a first argument other than a function... @@ -39,6 +51,19 @@ import curry = require( './index' ); curry( 'abc' ); // $ExpectError } +// The compiler throws an error if the function is provided a third argument which does not constitute a valid `this` context... +{ + const cxt = { + 'count': 0, + 'multiply': function multiply( this: { count: number }, x: number, y: number ): number { + this.count += 1; // eslint-disable-line no-invalid-this + return x * y; + } + }; + curry( cxt.multiply, { 'COUNT': 2 } ); // $ExpectError + curry( cxt.multiply, 2, {} ); // $ExpectError +} + // The compiler throws an error if the function is provided more than three arguments... { curry( ( x: number, y: number ): number => x + y, 2, {}, 4 ); // $ExpectError