How to reduce javascript object to only contain properties from interface

When using typescript a declared interface could look like this:

interface MyInterface {
  test: string;
}

And an implementation with extra property could be like this:

class MyTest implements MyInterface {
  test: string;
  newTest: string;
}

Example (here the variable 'reduced' still contain the property 'newTest'):

var test: MyTest = {test: "hello", newTest: "world"}

var reduced: MyInterface = test; // something clever is needed

Question

In a general way, how can you make the 'reduced' variable to only contain the properties declared in the 'MyInterface' interface.

Why

The problem occur when trying to use the 'reduced' variable with angular.toJson before sending it to a rest service - the toJson method transforms the newTest variable, even if it's not accessible on the instance during compile, and this makes the rest service not accept the json since it has properties that shouldn't be there.


Solution 1:

It is not possible to do this. The reason being interface is a Typescript construct and the transpiled JS code is empty

//this code transpiles to empty!
interface MyInterface {
  test: string;
}

Thus at runtime there is nothing to 'work with' - no properties exist to interrogate.

The answer by @jamesmoey explains a workaround to achieve the desired outcome. A similar solution I use is simply to define the 'interface' as a class -

class MyInterface {
  test: string = undefined;
}

Then you can use lodash to pick the properties from the 'interface' to inject into you object:

import _ from 'lodash';  //npm i lodash

const before = { test: "hello", newTest: "world"};
let reduced = new MyInterface();
_.assign(reduced , _.pick(before, _.keys(reduced)));
console.log('reduced', reduced)//contains only 'test' property

see JSFiddle

This is a pragmatic solution that has served me well without getting bogged down on semantics about whether it actually is an interface and/or naming conventions (e.g. IMyInterface or MyInterface) and allows you to mock and unit test

Solution 2:

TS 2.1 has Object Spread and Rest, so it is possible now:

var my: MyTest = {test: "hello", newTest: "world"}

var { test, ...reduced } = my;

After that reduced will contain all properties except of "test".