72 lines
1.6 KiB
JavaScript
72 lines
1.6 KiB
JavaScript
/**
|
|
* @template {(...args: any[]) => any} F
|
|
* @typedef {F extends ((...args: infer A) => any) ? A : never} Params
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} T
|
|
* @typedef {T extends [any, ...any[]] ? T[0] : never} Head
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} T
|
|
* @typedef {((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []} Tail
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} T
|
|
* @typedef {T extends ([] | [any]) ? false : true} HasTail
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} T
|
|
* @typedef {{ 0: Last<Tail<T>>; 1: Head<T> }[HasTail<T> extends true ? 0 : 1]} Last
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} T
|
|
* @typedef {T['length']} Length
|
|
*/
|
|
|
|
/**
|
|
* @template E
|
|
* @template {any[]} T
|
|
* @typedef {((head: E, ...args: T) => any) extends ((...args: infer U) => any) ? U : T} Prepend
|
|
*/
|
|
|
|
/**
|
|
* @template {number} N
|
|
* @template {any[]} T
|
|
* @template {any[]} [I = []]
|
|
* @typedef {{ 0: Drop<N, Tail<T>, Prepend<any, I>>; 1: T }[Length<I> extends N ? 1 : 0]} Drop
|
|
*/
|
|
|
|
/**
|
|
* @template X, Y
|
|
* @typedef {X extends Y ? X : Y} Cast
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} P, R
|
|
* @typedef {<T extends any[]>(...args: Cast<T, Partial<P>>) => Drop<Length<T>, P> extends [any, ...any[]] ? Curried<Cast<Drop<Length<T>, P>, any[]>, R> : R} Curried
|
|
*/
|
|
|
|
/**
|
|
* @template {any[]} P, R
|
|
* @param {(...args: P) => R} func
|
|
* @returns {Curried<P, R>}
|
|
*/
|
|
export function curry(func) {
|
|
return function curried(...args) {
|
|
if (args.length >= func.length) {
|
|
return func.apply(this, args)
|
|
} else {
|
|
/** @type {Curried<P, R>} */
|
|
return function(...args2) {
|
|
return curried.apply(this, args.concat(args2))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|