Best way of using Maybe in Purescript with JS object

I am trying to use Maybe in Purescript. I have a simple function like this:

getName :: { name :: Maybe String} -> String
getName { name: Just x } = x
getName { name: Nothing } = "No name"

And a JS object like this:

  const example = {
    name: 'Hello'
  }

when I run getName(example), it returns error:

Error: Failed pattern match at Utilities (line 53, column 1 - line 53, column 45): Object

I guess I have to lift the value of name up in example first in order for this to work? If I need to set it Just or Nothing by checking if any value exists there, is using isUndefined the way to go? Checking undefined in Purescript looks like how I would code in JS, thus I want to know if there is a better approach for this.

Well, the most idiomatic way of dealing with this in the PureScript side depends somewhat on your context. Are you working with data coming in from the FFI? The most typical thing to do there is to make your foreign .js file “sanitize” the types, by providing Just and Nothing to the JS code. So you might see something like

exports.getExample = function(Just) { 
  return function (Nothing) { 
    if (example.name === undefined) return { name: Nothing };
    else return { name: Just(example.name) };
  };
}

and then on the PureScript side, that would look like

foreign import getExample :: (String -> Maybe String) -> (Maybe String) -> { name :: Maybe String }

example :: { name :: Maybe String }
example = getExample Just Nothing

(Probably you’d actually use Fn2 and make the JS function uncurried).

Maybe you’re trying to decode some JSON value that might be null. In our code, we use argonaut, and we’ll have something like this:

newtype JsonMaybe a = JsonMaybe (Maybe a)
instance decodeJsonMaybe :: DecodeJson a => DecodeJson (JsonMaybe a) where
  decodeJson json  
    | isNull json = Right (JsonMaybe Nothing)
    | otherwise = do
      x <- decodeJson json
      pure (JsonMaybe (Just x))

which lets us decode something like the example object in your code like

type Example = { name :: Maybe String }
type ExampleJson = { name :: JsonMaybe String }

decodeExample :: Json -> Either String Example
decodeExample json = case decodeJson json of 
  Right ({ name :: JsonMaybe name } :: ExampleJson) -> Right { name }
  Left err -> Left err

(I’m a little annoyed that there isn’t an isUndefined in Argonaut, only isNull, so you’d have to build that yourself).

Are you able to share a bit more about your context?
Both the FFI and working with untyped JSON values are considered “advanced” concepts in PureScript, so don’t feel aggrevated if it gets really deep really fast - just hang in there!

I think the js side could also work like:

exports.getExample = Just => Nothing => ({ name: example.name === undefined ? Nothing : Just(example.name) })