Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean way to map objects to other objects?

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!

like image 223
mintychai Avatar asked Jul 17 '17 20:07

mintychai


People also ask

How do I map one object to another object in C#?

AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.

What will happen when two objects with map method?

With a map method, you can order any number of objects by calling each object's map method once to map that object to a position on the axis used for the comparison, such as a number or date.

Which is faster map or object?

The results are similar to those string-key cases: Map s start off as much faster than objects (2 times faster for insertion and deletion, 4-5 times faster for iteration), but the delta is getting smaller as we increase the size.

What is a mapped object?

A mapping object maps values of one type (the key type) to arbitrary objects. Mappings are mutable objects. There is currently only one mapping type, the dictionary . A dictionary's keys are almost arbitrary values.


2 Answers

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;
}
like image 51
Nitzan Tomer Avatar answered Oct 18 '22 00:10

Nitzan Tomer


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

like image 2
Mosh Feu Avatar answered Oct 17 '22 23:10

Mosh Feu