Repository: gcanti/tcomb (js)

Issue:
Interface filters additional props when props contain a struct
Version: 3.2.11

As per documentation, an `interface` should not filter additional props unless `strict = true`. However, when an interface contains a `struct` member (or, I believe, when there are non-identity types), additional props do get filtered out.

Here's a minimal console.log test:

```javascript
const t = require('tcomb')

const Point = t.struct({
  x: t.Number,
  y: t.Number
})

const PointInterface = t.inter({
  x: t.Number,
  y: t.Number
})

const HydrateInterface = t.inter({
  point: Point
})


console.log(PointInterface({
  x: 1,
  y: 2,
  extra: 3
}))

// Expected:
// { x: 1, y: 2, extra: 3 }
//
// Output (correct):
// { x: 1, y: 2, extra: 3 }


console.log(HydrateInterface({
  point: { x: 1, y: 2 },
  extra: 3
}))

// Expected:
// { point: Struct { x: 1, y: 2 }, extra: 3 }
//
// Output (incorrect):
// { point: Struct { x: 1, y: 2 } }
//
// The additional prop "extra" should not be filtered out
```

Pull request description:
now `interface` doesn't filter additional props when props contain a …
…struct, fix #245

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3164c71..735798a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,29 +12,34 @@
 **Note**: Gaps between patch versions are faulty/broken releases.
 **Note**: A feature tagged as Experimental is in a high state of flux, you're at risk of it changing without notice.
 
-# 3.2.11
+# v3.2.12
+
+- **Bug Fix**
+  - now `interface` doesn't filter additional props when props contain a struct, fix #245 (@gcanti)
+
+# v3.2.11
 
 - **Bug Fix**
   - allow declare'd unions with custom dispatch, fix #242 (@gcanti)
 
-# 3.2.10
+# v3.2.10
 
 - **Bug Fix**
   - handle nully values in interface `is` function (@gcanti)
 
-# 3.2.9
+# v3.2.9
 
 - **New Feature**
   - fromJSON: track error path, fix #235 (@gcanti)
 - **Internal**
   - change shallow copy in order to improve perfs (@gcanti)
 
-# 3.2.8
+# v3.2.8
 
 - **Bug Fix**
   - mixing types and classes in a union throws, fix #232 (@gcanti)
 
-# 3.2.7
+# v3.2.7
 
 - **Bug Fix**
   - add support for class constructors, `fromJSON` module (@gcanti)
diff --git a/lib/assign.js b/lib/assign.js
new file mode 100644
index 0000000..cfef6ca
--- /dev/null
+++ b/lib/assign.js
@@ -0,0 +1,8 @@
+function assign(x, y) {
+  for (var k in y) {
+    x[k] = y[k];
+  }
+  return x;
+}
+
+module.exports = assign;
\ No newline at end of file
diff --git a/lib/interface.js b/lib/interface.js
index ee78fa5..8f95c31 100644
--- a/lib/interface.js
+++ b/lib/interface.js
@@ -12,6 +12,7 @@ var getDefaultInterfaceName = require('./getDefaultInterfaceName');
 var isIdentity = require('./isIdentity');
 var is = require('./is');
 var extend = require('./extend');
+var assign = require('./assign');
 
 function extendInterface(mixins, name) {
   return extend(inter, mixins, name);
@@ -62,7 +63,7 @@ function inter(props, options) {
     }
 
     var idempotent = true;
-    var ret = {};
+    var ret = identity ? {} : assign({}, value);
     for (var prop in props) {
       var expected = props[prop];
       var actual = value[prop];
diff --git a/lib/update.js b/lib/update.js
index ea5c92f..372057f 100644
--- a/lib/update.js
+++ b/lib/update.js
@@ -3,17 +3,14 @@ var isObject = require('./isObject');
 var isFunction = require('./isFunction');
 var isArray = require('./isArray');
 var isNumber = require('./isNumber');
+var assign = require('./assign');
 
 function getShallowCopy(x) {
   if (isObject(x)) {
     if (x instanceof Date || x instanceof RegExp) {
       return x;
     }
-    var ret = {};
-    for (var k in x) {
-      ret[k] = x[k];
-    }
-    return ret;
+    return assign({}, x);
   }
   if (isArray(x)) {
     return x.concat();
diff --git a/package.json b/package.json
index 4b41cd2..2737c96 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "tcomb",
-  "version": "3.2.11",
+  "version": "3.2.12",
   "description": "Type checking and DDD for JavaScript",
   "main": "index.js",
   "typings": "index.d.ts",


Test patch:
diff --git a/test/interface.js b/test/interface.js
index 4e377b5..2c34a2f 100644
--- a/test/interface.js
+++ b/test/interface.js
@@ -97,6 +97,17 @@ describe('t.interface(props, [name])', function () {
     it('should hydrate fields', function () {
       var hi = HydrateInterface({ point: { x: 0, y: 1} });
       assert.equal(Point.is(hi.point), true);
+      var A = t.struct({ x: t.Number });
+      var B = t.inter({ a: A });
+      var actual = B({
+        a: { x: 1 },
+        extra: 3
+      });
+      assert.equal(actual.a instanceof A, true);
+      assert.deepEqual(actual, {
+        a: { x: 1 },
+        extra: 3
+      });
     });
 
     it('should handle strict option', function () {