點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Either 實現 Validation

Sam Xiao's Avatar 2021-04-21

針對 User 輸入做 Validation 時,若有任何錯誤則不再繼續執行,這種 Control Flow 正適合 Either。

Version

Vue 3.0.11
Sanctuary 3.1.0

Composition API

empty000

當輸入為空白時,按下 Submit 會顯示 name is empty

empty001

當輸入 Sam 時,按下 Submit 將顯示 Hello Sam

<template lang='pug'>
div
  input(v-model='name')
  button(@click='onClick') Submit
div {{ msg }}  
</template>

<script setup>
ref: name = ''
ref: msg = ''

let onClick = () => {
  if (name === '') msg = 'name is empty'
  else msg = `Hello ${name}`
}
</script>

12 行

let onClick = () => {
  if (name === '') msg = 'name is empty'
  else msg = `Hello ${name}`
}

Imperative 會使用 if else 判斷,將顯示結果直接寫入 msg state。

Either

empty000

結果不變,但使用 Either 改寫。

<template lang='pug'>
div
  input(v-model='name')
  button(@click='onClick') Submit
div {{ msg }}  
</template>

<script setup>
import { ref } from 'vue'
import { read, write } from 'vue3-fp'
import { pipe, isEmpty, ifElse, thunkify, concat, map } from 'ramda'
import { Left, Right, either, I } from 'sanctuary'

let name = ref('')
let msg = ref('')

let chkEmpty = ifElse(
  isEmpty,
  thunkify(Left)('name is empty'),
  Right
)

let onClick = pipe(
  read(name),
  chkEmpty,
  map(concat('Hello ')),
  either(I)(I),
  write(msg)
)
</script>

23 行

let onClick = pipe(
  read(name),
  chkEmpty,
  map(concat('Hello ')),
  either(I)(I),
  write(msg)
)

使用 pipe() 組合出 onClick()

  • read(name):讀出 name state
  • chkEmpty:檢查輸入是否為空白,並回傳 Either
  • map(concat('Hello ')):因為 chkEmpty() 回傳 Either,若要對 name state 作處理,必須將 function 包在 map() 才能修改 Either 內部值
  • either(I)(I):從 Either 內部讀出值
  • write(msg):寫入 name state

17 行

let chkEmpty = ifElse(
  isEmpty,
  thunkify(Left)('name is empty'),
  Right
)

使用 ifElse() 組合出 chkEmpty()

  • isEmpty:檢查輸入是否為空白
  • thunkify(Left)('name is empty'):若輸入為空白,則回傳 Left Either,相當於 Exception
  • Right:正常值則回傳 Right Either

Conclusion

  • 關鍵在於 Either 之後的值若需處理,必須統一放在 map() 內,類似 Promise 需在 then() 內處理,且只要是 Left Either,則 map() 內的 function 都不會執行,類似 Imperative 的 Exception

Reference

Sanctuary, Either