在本系列文中,所有的程式碼以及測試都可以在 should-i-use-fp-ts 找到,今日的範例放在 src/day-13 並且有習題和測試可以讓大家練習。
昨天的示範中有使用到兩個函數 O.fromNullable 以及 O.fromPredicate,這兩個函式可以用來判斷當前的變數是否合法,以下是 O.fromNullable 的定義,如果當前變數(x)是 undefined 或是 null 就回傳 O.none,否則回傳 O.some(x)。
/** If x is null or undefined, return O.none, else O.some(x) */
type FromNullable = <A>(x: A) => O.Option<NonNullable<A>>;
const fromNullable: FromNullable = x => x === undefined || x === null ? O.none : O.some(x)
O.fromPredicate 的使用方法可以視為 Array.filter 在 Option 中的實作,一樣是傳入一個 predicate function ((x: A) => boolean) 來判斷變數是否合法,是則回傳 O.some(x) 否則回傳 O.none。
/** If predicate(x) is true, return O.some(x), else O.none */
type FromPredicate = <A>(predicate: (x: A) => boolean) => (x: A) => O.Option<A>;
/** fromPredicate need to inject predicate function first(to validate following variable) */
const fromPredicate: FromPredicate = predicate => x => predicate(x) ? O.some(x) : O.none;
這兩項函數在日常中有很高的使用率,以下用一個 request 來做範例。
先定義 request 的 type: Req
type Req = { query: { str?: string; id: number } };
str 的部分我們可以使用 O.fromNullable 來判斷是否為空。
const isStringEmpty = (req: Req) => pipe(
req.query.str,
O.fromNullable,
O.map(str => `${str} is not empty`),
O.getOrElse(() => 'is empty'),
);
id 的部分可以用 O.fromPredicate 來判斷是否合法 (id > 0)
const isIdValid = (req: Req) => pipe(
req.query.id,
O.fromPredicate(id => id > 0),
O.map(id => `${id} is valid`),
O.getOrElse(() => 'is invalid'),
);
今天的主題在 should-i-use-fp-ts src/day-13 有習題和測試可以練習,大家可以嘗試自己能不能寫出自己的 fromNullable , fromPredicate。