/** @module function/bindStrict.ts */
import defineFunctionProperties from './defineFunctionProperties'
const bindSymbol = Symbol( 'bind' )
/**
* bindStrict works like bind however it is typed so that a
* function bound to all of its parameters can only be invoked
* by passing an `undefined` value to it.
* @example
* const addThree = (a: number, b: number, c: number ) => a + b + c
* const bound2 = bindStrict( addThree, 1, 2 )
* const result = bound2( 3 ) // 6
* const bound3 = bindStrict( addThree, 1, 2, 3 )
* bound3() // works, 6
* bound3( 4 ) // will not typecheck
*/
export function bindStrict, Z>( fn: ( a: A, ...args: Y ) => Z, a: A ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, ...args: Y ) => Z, a: A, b: B ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, ...args: Y ) => Z, a: A, b: B, c: C ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, ...args: Y ) => Z, a: A, b: B, c: C, d: D ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V, w: W, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V, w: W ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
export function bindStrict, Z>( fn: ( a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V, w: W, x: X, ...args: Y ) => Z, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L, m: M, n: N, o: O, p: P, q: Q, r: R, s: S, t: T, u: U, v: V, w: W, x: X ): ( ...args: Y extends ( Y['length'] extends 0 ? never : Y ) ? Y : void[] ) => Z
/**
* bindStrict works like bind however it is typed so that a
* function bound to all of its parameters can only be invoked
* by passing an `undefined` value to it.
* @example
* const addThree = (a: number, b: number, c: number ) => a + b + c
* const bound2 = bindStrict( addThree, 1, 2 )
* const result = bound2( 3 ) // 6
* const bound3 = bindStrict( addThree, 1, 2, 3 )
* bound3() // works, 6
* bound3( 4 ) // will not typecheck
*/
export function bindStrict( this: unknown, fn, ...args ) {
// tslint:disable-next-line:variable-name
return ( args.length >= fn.length
? this === bindSymbol
? fn( ...args )
: defineFunctionProperties( () => fn( ...args ), { length: 0 } )
: defineFunctionProperties( bindStrict.bind( bindSymbol, fn, ...args ), {
length: fn.length - args.length,
// name: fn.name,
} )
)
}
export default bindStrict