點燈坊

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

使用 propIs() 判斷 Object Property 型別

Sam Xiao's Avatar 2019-09-23

Ramda 的 is() 相當於 instanceOf 的 Function 版本,實務上我們我們常需要對 Object 的 Property 判斷 Type,Ramda 也提供了 propIs()

Version

macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.251
Ramda 0.26.1

Functional

import { pipe, prop, is } from 'ramda';

let data = {
  name: 'Sam'
};

let propIs = type => name => pipe(
  prop(name),
  is(type)
);

let fn = propIs(String)('name');

fn(data); // ?

data 為 object,我們想判斷其 name property 是否為 String type。

根據過去的經驗,我們知道 prop() 可讀取 property,is() 可判斷 type,因此可輕易組合 prop()is() 產生新的 propIs()

propis000

Point-free

import { pipe, prop, is, flip, useWith } from 'ramda';

let data = {
  name: 'Sam'
};

let propIs = flip(useWith(
  pipe, [prop, is]
));

let fn = propIs(String)('name');

fn(data); // ?

挑戰一下自己,是否能夠將 propIs() 重構成 point-free 呢 ?

其實由剛剛的 propIs() 可知,pipe() 才是最後要執行的 main function,prop()is() 其實都是 parameter 的 transformer function 而已,因此可以使用 useWith() 使其 point-free。

但可惜我們第一個參數是 type,與我們用 useWith() 的 signature 不合,因此再使用 flip() 加以顛倒。

propis001

Function Composition

import { compose, prop, is, useWith } from 'ramda';

let data = {
  name: 'Sam'
};

let propIs = useWith(
  compose, [is, prop]
);

let fn = propIs(String)('name');

fn(data); // ?

既然能使用 pipe() 達成 pipeline,反向使用 compose() 就是 function composition 了。

而且因為 compose() 使 signature 顛倒,連 flip() 都省下來了。

propis003

Ramda

import { propIs } from 'ramda';

let data = {
  name: 'Sam'
};

let fn = propIs(String)('name');

fn(data); // ?

事實上 Ramda 已經提供了 propIs(),可直接使用。

propIs()
Type → String → Object → Boolean
直接判斷 Property 型別

Type:要判斷的 type,為 constructor

String:要判斷 object 的 property 名稱

Object:data 為 object

Boolean:回傳判斷結果

propis002

Conclusion

  • 儘管不知道 Ramda 的 propIs(),也可自行由 prop()is() 組合出來,這正是 function composition 的威力

Reference

Ramda, propIs()
Ramda, prop()
Ramda, is()
Ramda, pipe()
Ramda, useWith()
Ramda, flip()
Ramda, compose()