Javascript object generation
Every request body, request response, message on web socket, entity, dto in Emi are called 'object'. The object is generated based on fields array, which can be nested, of course. Emi uses the same function for generting different type of classes.
Javascript classes vs objects
When working with APIs, it’s tempting to just define a TypeScript type and fetch data. For example:
type Post = { userId: number; id: number; title: string; body: string };
async function fetchPost(id: number): Promise<Post> {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  return res.json();
}
// Example usage
fetchPost(1).then(post => {
  console.log("Title:", post.title);
});
This looks fine at first glance, but it has some important problems:
Problems with plain types
- 
Backend drift The backend may evolve over time. Fields might be renamed, removed, or added. Your TypeScript types won’t catch this at runtime — they only exist at compile time. 
- 
No defaults If the backend omits a field, you’ll end up with undefined. There’s no way to guarantee initialized values, which makes your code brittle.
- 
Runtime unsafety Even if TypeScript says everything is fine, the actual JSON from the server might be malformed or missing required fields. TypeScript does not validate data at runtime. 
Solution: Use Classes
By wrapping responses into classes, we get:
- Defaults for missing fields
- Runtime-safe construction of objects
- A clean place for helper methods
- Extending them and embed the extra logic in single place rather than functions scattered across the app.
Take a look at the rewritten mechanism, this time using classes:
class Post {
  userId: number;
  id: number;
  title: string;
  body: string;
  constructor(data: Partial<Post>) {
    this.userId = data.userId ?? 0;
    this.id = data.id ?? 0;
    this.title = data.title ?? "Untitled";
    this.body = data.body ?? "";
  }
  static async fetch(id: number): Promise<Post> {
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
    const json = await res.json();
    return new Post(json);
  }
  shortBody(): string {
    return this.body.slice(0, 50) + "...";
  }
}
// Usage
(async () => {
  const post = await Post.fetch(1);
  console.log("Title:", post.title);
  console.log("Preview:", post.shortBody());
})();
Now, this is much more reliable code instead of just typing them, you almost never get undefined. But still, writing that manually is a hassle, and type checking and other tools might be lost. Now, let's take a look how this could be generated using Emi js compiler:
- name: userId
  type: int64
- name: id
  type: int64
- name: title
  type: string
- name: body
  type: string
And Emi compiler would generate such shopisticated details (content is a bit long but worth to take a look at it.) Emi compiler generates ts type and, class, with full getter, setters and validators for each field.
/**
 * The base class definition for anonymouse
 **/
export class Anonymouse {
  /**
   *
   * @type {number}
   **/
  #userId = 0;
  /**
   *
   * @returns {number}
   **/
  get userId() {
    return this.#userId;
  }
  /**
   *
   * @type {number}
   **/
  set userId(value) {
    const correctType = typeof value === "number";
    const parsedValue = correctType ? value : Number(value);
    if (!Number.isNaN(parsedValue)) {
      this.#userId = parsedValue;
    }
  }
  setUserId(value) {
    this.userId = value;
    return this;
  }
  /**
   *
   * @type {number}
   **/
  #id = 0;
  /**
   *
   * @returns {number}
   **/
  get id() {
    return this.#id;
  }
  /**
   *
   * @type {number}
   **/
  set id(value) {
    const correctType = typeof value === "number";
    const parsedValue = correctType ? value : Number(value);
    if (!Number.isNaN(parsedValue)) {
      this.#id = parsedValue;
    }
  }
  setId(value) {
    this.id = value;
    return this;
  }
  /**
   *
   * @type {string}
   **/
  #title = "";
  /**
   *
   * @returns {string}
   **/
  get title() {
    return this.#title;
  }
  /**
   *
   * @type {string}
   **/
  set title(value) {
    this.#title = String(value);
  }
  setTitle(value) {
    this.title = value;
    return this;
  }
  /**
   *
   * @type {string}
   **/
  #body = "";
  /**
   *
   * @returns {string}
   **/
  get body() {
    return this.#body;
  }
  /**
   *
   * @type {string}
   **/
  set body(value) {
    this.#body = String(value);
  }
  setBody(value) {
    this.body = value;
    return this;
  }
  constructor(data) {
    if (data === null || data === undefined) {
      return;
    }
    if (typeof data === "string") {
      this.applyFromObject(JSON.parse(data));
    } else if (this.#isJsonAppliable(data)) {
      this.applyFromObject(data);
    } else {
      throw new Error(
        "Instance cannot be created on an unknown value, check the content being passed. got: " +
          typeof data,
      );
    }
  }
  #isJsonAppliable(obj) {
    const g = globalThis;
    const isBuffer =
      typeof g.Buffer !== "undefined" &&
      typeof g.Buffer.isBuffer === "function" &&
      g.Buffer.isBuffer(obj);
    const isBlob = typeof g.Blob !== "undefined" && obj instanceof g.Blob;
    return (
      obj &&
      typeof obj === "object" &&
      !Array.isArray(obj) &&
      !isBuffer &&
      !(obj instanceof ArrayBuffer) &&
      !isBlob
    );
  }
  /**
   * casts the fields of a javascript object into the class properties one by one
   **/
  applyFromObject(data = {}) {
    const d = data;
    if (d.userId !== undefined) {
      this.userId = d.userId;
    }
    if (d.id !== undefined) {
      this.id = d.id;
    }
    if (d.title !== undefined) {
      this.title = d.title;
    }
    if (d.body !== undefined) {
      this.body = d.body;
    }
  }
  /**
   *	Special toJSON override, since the field are private,
   *	Json stringify won't see them unless we mention it explicitly.
   **/
  toJSON() {
    return {
      userId: this.#userId,
      id: this.#id,
      title: this.#title,
      body: this.#body,
    };
  }
  toString() {
    return JSON.stringify(this);
  }
  static get Fields() {
    return {
      userId: "userId",
      id: "id",
      title: "title",
      body: "body",
    };
  }
  /**
   * Creates an instance of Anonymouse, and possibleDtoObject
   * needs to satisfy the type requirement fully, otherwise typescript compile would
   * be complaining.
   **/
  static from(possibleDtoObject) {
    return new Anonymouse(possibleDtoObject);
  }
  /**
   * Creates an instance of Anonymouse, and partialDtoObject
   * needs to satisfy the type, but partially, and rest of the content would
   * be constructed according to data types and nullability.
   **/
  static with(partialDtoObject) {
    return new Anonymouse(partialDtoObject);
  }
  copyWith(partial) {
    return new Anonymouse({ ...this.toJSON(), ...partial });
  }
  clone() {
    return new Anonymouse(this.toJSON());
  }
}
As you see, there is a lot of details handled in such object generation, to make sure
the data integrity is kept in perfect level both in compile time and run time.
Performance and usage concerns
Generating such classes is very common on most programming languages, but in javascript it might be a bit of concern, mainly for following reasons:
- Using getField and setField functions, is slower than directly accessing .field property of an object.
- Setting value using js path, such as set('field.user.address[0].stree', 'New street') might be compromised
Comparing the performance
Let's make an interactive comparison, how slower it would be and you'll be suprised getters and setters are faster in some environments.
It looks odd at first, but the reason getter/setter sometimes beats direct property access comes down to how modern JavaScript engines optimize. A plain object can change shape at any time, which makes the engine cautious and may cause de-optimizations during tight loops. By contrast, a class with fixed methods has a stable shape, so the JIT compiler can inline and optimize those calls very aggressively. On top of that, microbenchmarks can be misleading: if values aren’t used in a meaningful way, the engine may partially skip or simplify the operations. In practice, the difference is just a few milliseconds across millions of iterations, so for real-world code, both approaches are effectively free. I prefer this response
// simple object
const obj: any = {};
for (let i = 0; i < 100000; i++) {
  obj.str = "Hello";
  obj.num = 42;
  obj.obj = { k: "v" };
  obj.arr = [1, 2, 3];
  const x1 = obj.str;
  const x2 = obj.num;
  const x3 = obj.obj;
  const x4 = obj.arr;
}
// class object
const o = new TestClass();
for (let i = 0; i < 100000; i++) {
  o.setStr("Hello");
  o.setNum(42);
  o.setObj({ k: "v" });
  o.setArr([1, 2, 3]);
  const x1 = o.getStr();
  const x2 = o.getNum();
  const x3 = o.getObj();
  const x4 = o.getArr();
}As you might see, the numbers are very close, and in real life, you would not call millions of times one after each other a javascript setter. Hence, Emi compiler extra checks make sense to bring the safety into the code base.