Is there a good way to map objects to other objects? Library recommendations welcome too.
For example, say I have these classes:
export class Draft {
id: number;
name: string;
summary: string;
}
export class Book {
id: number;
name: string;
info: Info;
}
export class Info {
value: string;
}
Traditionally, to map fields from Draft
to Book
I'd have to do so manually for each field:
export class Book {
[...]
fromDraft(Draft draft) {
this.id = draft.id;
this.name = draft.name;
this.info = new Info();
this.info.value = draft.summary;
}
}
Is there an easier way to map object fields that are named the same way? For example Draft
and Book
's id
and name
fields, while also being able to define custom mappings, like from draft.summary
to book.info.value
.
Note that this is far from my actual use case. Here it's not so bad to do assignments manually, but for objects with many similarly named fields it's quite a chore.
Thanks!
Regardless of TypeScript, you can use lodash _.mergeWith
and pass your merge function.
Advantage: More generic (If you have more logic you can add it (for complex types for example)
Disadvantage: You need lodash
Something like:
var a = {
foo: [1, 2, 3],
bar: true
}
var b = {
foo: [4, 5, 6, 7],
bar: false
}
var c = _.mergeWith(a, b, function(a, b) {
if (a.concat) {
return a.concat(b);
}
else {
return b;
}
})
console.log('c', c);
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>
http://jsbin.com/xugujon/edit?html,js
With regards to copying properties of the same name, you can use Object.assign:
fromDraft(Draft draft) {
Object.assign(this, draft);
this.info = new Info();
this.info.value = draft.summary;
}
The problem is that it will also create this.summary
, but it's a convenient way of copying properties so if you can model your classes differently then you can use it.
Another option is to have a list of shared property names and then iterate it:
const SHARED_NAMES = ["id", "name"];
fromDraft(Draft draft) {
SHARED_NAMES.forEach(name => this[name] = draft[name]);
this.info = new Info();
this.info.value = draft.summary;
}