iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 27
1

現在我們宣告定義一個 "柯里化 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>;

上一篇
動手做柯里化 - 26
下一篇
快取柯里化 - 28
系列文
為什麼世界需要Typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言