假设我的PureScript代码中的用户记录具有以下类型:
{ id :: Number
, username :: String
, email :: Maybe String
, isActive :: Boolean
}
Run Code Online (Sandbox Code Playgroud)
CommonJS模块源自PureScript代码.导出的用户相关函数将从外部JavaScript代码调用.
在JavaScript代码中,"用户"可以表示为:
var alice = {id: 123, username: 'alice', email: 'alice@example.com', isActive: true};
Run Code Online (Sandbox Code Playgroud)
email
可能是null
:
var alice = {id: 123, username: 'alice', email: null, isActive: true};
Run Code Online (Sandbox Code Playgroud)
email
可省略:
var alice = {id: 123, username: 'alice', isActive: true};
Run Code Online (Sandbox Code Playgroud)
isActive
可以省略,在这种情况下,假设true
:
var alice = {id: 123, username: 'alice'};
Run Code Online (Sandbox Code Playgroud)
id
遗憾的是有时候是一个数字字符串:
var alice = {id: '123', username: 'alice'};
Run Code Online (Sandbox Code Playgroud)
上面的五个JavaScript表示是等效的,应该生成等效的PureScript记录.
如何编写一个带有JavaScript对象并返回用户记录的函数?它将使用null /省略的可选字段的默认值,将字符串强制id
转换为数字,如果缺少必填字段或值类型错误则抛出.
我能看到的两种方法是在PureScript模块中使用FFI或在外部JavaScript代码中定义转换函数.后者似乎毛茸茸:
function convert(user) {
var rec = {};
if (user.email == null) {
rec.email = PS.Data_Maybe.Nothing.value;
} else if (typeof user.email == 'string') {
rec.email = PS.Data_Maybe.Just.create(user.email);
} else {
throw new TypeError('"email" must be a string or null');
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
我不确定FFI版本是如何工作的.我还没有使用过效果.
对不起,这个问题不是很清楚.我还没有足够的理解来确切知道我想知道的是什么.
我已经提出了一个解决方案.我敢肯定,很多可以改进,如改变的类型toUser
来Json -> Either String User
和保存的错误信息.如果您能看到改进此代码的任何方法,请发表评论.:)
除了一些核心模块之外,该解决方案还使用PureScript-Argonaut.
module Main
( User()
, toEmail
, toId
, toIsActive
, toUser
, toUsername
) where
import Control.Alt ((<|>))
import Data.Argonaut ((.?), toObject)
import Data.Argonaut.Core (JNumber(), JObject(), Json())
import Data.Either (Either(..), either)
import Data.Maybe (Maybe(..))
import Global (isNaN, readFloat)
type User = { id :: Number
, username :: String
, email :: Maybe String
, isActive :: Boolean
}
hush :: forall a b. Either a b -> Maybe b
hush = either (const Nothing) Just
toId :: JObject -> Maybe Number
toId obj = fromNumber <|> fromString
where
fromNumber = (hush $ obj .? "id")
fromString = (hush $ obj .? "id") >>= \s ->
let id = readFloat s in if isNaN id then Nothing else Just id
toUsername :: JObject -> Maybe String
toUsername obj = hush $ obj .? "username"
toEmail :: JObject -> Maybe String
toEmail obj = hush $ obj .? "email"
toIsActive :: JObject -> Maybe Boolean
toIsActive obj = (hush $ obj .? "isActive") <|> Just true
toUser :: Json -> Maybe User
toUser json = do
obj <- toObject json
id <- toId obj
username <- toUsername obj
isActive <- toIsActive obj
return { id: id
, username: username
, email: toEmail obj
, isActive: isActive
}
Run Code Online (Sandbox Code Playgroud)
更新:我根据Ben Kolera 的要点改进了上面的代码.
你有没有看过purescript-foreign
(https://github.com/purescript/purescript-foreign)?我想这就是你在这里寻找的东西。