> For the complete documentation index, see [llms.txt](https://modelico.javiercejudo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://modelico.javiercejudo.com/basics/optional_values.md).

# 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](https://github.com/javiercejudo/modelico/tree/c356c97466264d859bea3d0ad8f9542f3bfd0894/docs/introduction/README.md):

```javascript
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`

## Using `withDefault`

The `withDefault` metadata takes some metadata and a default value which will be used only if the property is `null` or missing.

```javascript
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:

```javascript
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
```

## Maybes

```javascript
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:

```javascript
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.*
