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".