在本系列文中,所有的程式碼以及測試都可以在 should-i-use-fp-ts 找到,今日的範例放在 src/day-15 並且有習題和測試可以讓大家練習。
昨天學習了 O.Do 以及 O.bind,但使用起來有點繁瑣。
// use x = 2 as example
const verbose = (x: number) => pipe(
O.Do, // { _tag: 'Some', value: {} }
O.bind('x', () => O.of(x)), // { _tag: 'Some', value: { x: 2 } }
);
上述兩行中有實際邏輯意義的部分只有 O.bind('x', () => O.of(x)),這個部分有點像是之前的 O.map + O.flatten,這種行為可以另外設計一個函數來簡化,讓 pipe 中的邏輯更加精粹。
這邊開始實作 bindTo,一樣先從型別開始定義。
type BindTo = <N extends string>(name: N) => <A>(fa: O.Option<A>) => O.Option<{ readonly [K in N]: A }>;
bindTo 和 bind 非常類似,一樣是先傳入 property 的名稱,之後傳入要注入這個 property 的生成函式。
接著定義 bindTo 的行為。
const bindTo: BindTo = name => fa => pipe(
fa,
O.map(a => ({ [name]: a } as any)),
);
由於使用 bindTo 的情境是沒有 Do 的,所以函式行為比 bind 更單純,將 fa 運算結果放入 Option<Object> 即可。
以下是實際使用的範例。
// use x = 2 as example
export const simple = (x: number) => pipe(
O.of(x), // { _tag: 'Some', value: 2 }
O.bindTo('x'), // { _tag: 'Some', value: { x: 2 } }
);
如此一來,pipe 之中只含有重要的訊息。
x 轉入 Option 的領域。x 之中。不再有雞肋的 O.Do 佔領版面,整個 pipe 變的更加簡要。
今天的主題在 should-i-use-fp-ts src/day-15 有習題和測試可以練習,大家可以嘗試自己能不能寫出自己的 bindTo。