Optional / null values
By design, all fields are required, ie.
null
or missing fields will cause a TypeError
while reviving. In the case of the Animal
class from the introductory example:const pet = M.fromJSON(Animal, '{"name": null}')
// => TypeError: no value for key "name"
To support missing properties or
null
values, you can either use withDefault
or declare the property as a Maybe
The
withDefault
metadata takes some metadata and a default value which will be used only if the property is null
or missing.import M from 'modelico'
const {string, maybe} = M.metadata()
class Animal extends M.Base {
// ... same as before
static innerTypes () {
return Object.freeze({
name: withDefault(string(), 'Unknown')
})
}
}
Then, it can be used as any other value:
const pet1 = M.fromJSON(Animal, '{"name": "Bane"}')
const pet2 = M.fromJSON(Animal, '{"name": null}')
const pet3 = M.fromJSON(Animal, '{}')
pet1.name() // => Bane
pet2.name() // => Unknown
pet3.name() // => Unknown
import M from 'modelico'
const {string, maybe} = M.metadata()
class Animal extends M.Base {
// ... same as before
static innerTypes () {
return Object.freeze({
name: maybe(string())
})
}
}
Then, we can use it as follows:
const pet1 = M.fromJSON(Animal, '{"name": "Bane"}')
// pet2 and pet3 behave the same way
const pet2 = M.fromJSON(Animal, '{"name": null}')
const pet3 = M.fromJSON(Animal, '{}')
pet1.name().isEmpty() // => false
pet1.name().getOrElse('Coco') // => Bane
JSON.stringify(pet1) // => {"name":"Bane"}
pet2.name().isEmpty() // => true
pet2.name().getOrElse('Bane') // => Bane
JSON.stringify(pet2) // => {"name":null}
pet3.name().isEmpty() // => true
pet3.name().getOrElse('Bane') // => Bane
JSON.stringify(pet3) // => {"name":null}
Note:
pet2
does not produce the same JSON it was parsed from. If that is important to you, one possibility would be to not declare the name
field and use M.fields(pet2).name
to check for its presence and value manually.Last modified 2yr ago