點燈坊

戦わなければ、勝てない

使用 defaultTo() 提供 undefined 預設值

Sam Xiao's Avatar 2020-03-16

Ramda 有些 Function 會回傳 undefined,如 find()prop(),此時可使用 defaultTo() 使 Pipeline 繼續。

Version

macOS Catalina 10.15.3
VS Code 1.43.0
Quokka 1.0.282
Ramda 0.27.0

find()

import { find, pipe, propEq, isNil, always, when } from 'ramda'

let data = [
  { id: 1, title: 'FP in JavaScript', price: 100 },
  { id: 2, title: 'RxJS in Action', price: 200 },
  { id: 3, title: 'Speaking JavaScript', price: 300 }
]

let f = d => v => pipe(
  find(propEq('title', v)),
  when(isNil, always(d))
)

f('N/A')('FP in JavaScript')(data) // ?
f('N/A')('FP')(data) // ?

Ramda 的 find() 是典型會回傳 undefined 的 function,若想回傳 undefined 時就顯示 預設值

標準會使用 when()isNil() 判斷,若為 undefined() 則使用 always() 回傳預設值。

default000

defaultTo()

import { find, defaultTo, pipe, propEq } from 'ramda'

let data = [
  { id: 1, title: 'FP in JavaScript', price: 100 },
  { id: 2, title: 'RxJS in Action', price: 200 },
  { id: 3, title: 'Speaking JavaScript', price: 300 }
]

let f = d => v => pipe(
  find(propEq('title', v)),
  defaultTo(d)
)

f('N/A')('FP in JavaScript')(data) // ?
f('N/A')('FP')(data) // ?

比較簡單的方式是使用 defaultTo() 直接提供 undefined 的預設值即可。

defaultTo()
a → b → a | b
若第一個 argument 為 nullundefinedNaN,則回傳第二個 argument,否則回傳第一個 argument

a:原始 data

b:若 data 為 nullundefinedNaN,要回傳的預設值

a | b:回傳 ab

default001

prop()

import { pipe, prop, when, isNil, always } from 'ramda'

let data = {
  title: 'FP in JavaScript'
}

let f = d => k => pipe(
  prop(k),
  when(isNil, always(d))
)

f('N/A')('title')(data) // ?
f('N/A')('price')(data) // ?

若 property 不存在,prop() 也會回傳 undefined,同理也可使用 when() 搭配 isNil() 判斷。

default002

defaultTo()

import { defaultTo, pipe, prop } from 'ramda'

let data = {
  title: 'FP in JavaScript'
}

let f = d => k => pipe(
  prop(k),
  defaultTo(d)
)

f('N/A')('title')(data) // ?
f('N/A')('price')(data) // ?

同理也可使用 defaultTo() 取代 when()isNil()

default003

Point-free

import { defaultTo, pipe, prop, useWith, flip } from 'ramda'

let data = {
  title: 'FP in JavaScript'
}

let f = flip(useWith(
  pipe, [prop, defaultTo]
))

f('N/A')('title')(data) // ?
f('N/A')('price')(data) // ?

也可使用 useWith() 使 f() 能 point-free。

default004

propOr()

import { propOr } from 'ramda'

let data = {
  title: 'FP in JavaScript'
}

let f = propOr

f('N/A')('title')(data) // ?
f('N/A')('price')(data) // ?

對於這常見需求,Ramda 已經內建 propOr() 可直接使用。

default005

Conclusion

  • 若出現 when()isNil() 判斷,別忘了重構成 defaultTo()

Reference

Ramda, defaultTo()
Ramda, find()
Ramda, propEq()
Ramda, prop()
Ramda, propOr()
Ramda, flip()
Ramda, useWith()