現在我們宣告定義一個 "柯里化 add函數" 的方法
declare function curry<T extends number[]>(addFunc: (...args: T) => number): CurryAddX<T>;
上面程式碼 curry 是一個泛型方法, T 是泛型, 表明了只接受 number 陣列.
curry 方法只接受 addFunc 一個參數, 然後這個 addFunc 參數類型是泛型 T.
curry 方法傳回值是一個 CurryAddX 類型.
完整的 curry 程式碼如下
type CurryAdd1 = (a: number) => number;
type CurryAdd2 = {
(a:number): CurryAdd1;
(a:number, b: number): number;
};
type CurryAdd3 = {
(a: number): CurryAdd2;
(a: number, b: number): CurryAdd1;
(a: number, b: number, c: number): number;
};
type CurryAddX<T> =
T extends [number, number, number] ? CurryAdd3 :
T extends [number, number] ? CurryAdd2 :
T extends [number] ? CurryAdd1 :
unknown
;
declare function curry<T extends number[]>
(fn: (...args: T) => number): CurryAddX<T>;
最後我們可以這樣用了, 真正的將 "加法函數" 柯里化為 "curryAdd" 函數
const curryAdd = curry((a: number, b: number) => a + b);
到目前為止, 我們創造的 curry 柯里化函數, 只能將一般函數(帶有number 參數) 柯里化, 我們還需要其他參數類型的柯里化方法.
我們可以把 curry 泛型函數中再一次泛型化. 我們先回頭看剛剛的程式碼
type CurryAdd1 = (a: number) => number;
type CurryAdd2 = {
(a: number, b:number): number;
(a: number): CurryAdd1;
};
type CurryAdd3 = {
(a: number, b:number, c:number): number;
(a: number, b:number): CurryAdd1;
(a: number): CurryAdd2;
};
type CurryAddX<T> =
T extends [number, number, number] ? CurryAdd3 :
T extends [number, number] ? CurryAdd2 :
T extends [number] ? CurryAdd1 :
unknown
;
declare function curry<T extends number[]>(addFunc: (...args: T) => number): CurryAddX<T>;
我們先將上段程式碼中所有 "回傳值" 進行泛型化
type CurryAdd1 = (a: number) => number;
泛型化的程式碼變成如下
type CurryAdd1<R> = (a: number) => R;
以此類推, 繼續泛型化其他的 "回傳值", 故上面整個程式碼看起來如下
type CurryAdd1<R> = (a: number) => R;
type CurryAdd2<R> = {
(a: number, b:number): R;
(a: number): CurryAdd1<R>;
};
type CurryAdd3<R> = {
(a: number, b:number, c:number): R;
(a: number, b:number): CurryAdd1<R>;
(a: number): CurryAdd2<R>;
};
type CurryAddX<T, R> =
T extends [number, number, number] ? CurryAdd3<R> :
T extends [number, number] ? CurryAdd2<R> :
T extends [number] ? CurryAdd1<R> :
unknown
;
declare function curry<T extends number[], R>(addFunc: (...args: T) => R): CurryAddX<T, R>;
接下來我們再將上面程式碼所有的 "輸入參數" 也泛型化
type CurryAdd1<A, R> = (a: A) => R;
type CurryAdd2<A, B, R> = {
(a: A, b: B): R;
(a: A): CurryAdd1<B, R>;
};
type CurryAdd3<A, B, C, R> = {
(a: A, b: B, c: C): R;
(a: A, b: B): CurryAdd1<C, R>;
(a: A): CurryAdd2<B, C, R>;
};
為了讓 CurryAddX 用上面新的泛型參數, 需要用點技巧
type CurryAddX<T, R> =
T extends [any, any, any] ? CurryAdd3<T[0], T[1], T[2], T[3], R> :
T extends [any, any] ? CurryAdd2<T[0], T[1], R> :
T extends [any] ? CurryAdd1<T[0], R> :
unknown
;
declare function curry<T extends any[], R>(addFunc: (...args: T) => R): CurryAddX<T, R>;