Repository: gcanti/tcomb (js)

Issue:
t.maybe setting the value to null when missing
Is there a reason why [`t.maybe` sets the value to `null` when missing](https://github.com/gcanti/tcomb/blob/master/lib/maybe.js#L34)?

This behavior turns a missing value (e.g. `undefined`) into a value (`null`) and it looks like a potentially undesirable side-effect.

For instance this causes issues with [`tcomb-react`](https://github.com/gcanti/tcomb-react): since `null` is a valid value, React will not use the value provided by `defaultProps`.

```js
@props({
  foo: t.maybe(String)
})
class MyComponent extends React.Component {
  
  static defaultProps = {
    foo: 'bar'
  }

  ...
}

<MyComponent /> // Invalid value null supplied to foo
```

A more natural implementation would look like

```js
return Nil.is(value) ? value : create(type, value, path);
```

Do you think that's reasonable, @gcanti?

Pull request description:
Prevent Maybe constructor from altering the value when Nil (fixes #183)
As discussed in #183, `maybe(MyType)(x)` currently returns `null` if `Nil.is(x)` returns `true`.

This may surprise users that would expect `maybe(MyType)(undefined)` to return `undefined`.

This PR changes the behavior of the `Maybe` constructor, so that `Nil` values are returned untouched by the constructor.

Patch:
diff --git a/lib/maybe.js b/lib/maybe.js
index 9813666..4d478d7 100644
--- a/lib/maybe.js
+++ b/lib/maybe.js
@@ -31,7 +31,7 @@ function maybe(type, name) {
     if (process.env.NODE_ENV !== 'production') {
       forbidNewOperator(this, Maybe);
     }
-    return Nil.is(value) ? null : create(type, value, path);
+    return Nil.is(value) ? value : create(type, value, path);
   }
 
   Maybe.meta = {


Test patch:
diff --git a/test/maybe.js b/test/maybe.js
index f332c43..2bc0e47 100644
--- a/test/maybe.js
+++ b/test/maybe.js
@@ -63,7 +63,7 @@ describe('t.maybe(type, [name])', function () {
     it('should hydrate the elements of the maybe in production', util.production(function () {
       var T = t.maybe(Point);
       assert.deepEqual(T(null), null);
-      assert.deepEqual(T(undefined), null);
+      assert.ok(typeof T(undefined) === 'undefined');
       assert.ok(Point.is(T({x: 0, y: 0})));
     }));
 
@@ -85,6 +85,12 @@ describe('t.maybe(type, [name])', function () {
       assert.equal(p1 === p2, true);
     }));
 
+    it('should be idempotent on Nil values', function () {
+      var T = t.maybe(t.String, 'T');
+      assert.deepEqual(T(null), null);
+      assert.ok(typeof T(undefined) === 'undefined');
+    });
+
   });
 
   describe('is(x)', function () {