¿Cuántas veces y de cuántas maneras has comparado objetos? Y no nos referimos en tu día a día cuando te vas de viaje o trabajar; nos referimos al mundo de la programación. Conoces la respuesta a la pregunta y sí, son innumerables. Sea en un lenguaje u otro, desde objetos simples hasta los más complejos, comparando si un objeto es igual a otro.

Si es así, seguramente habrás buscado y creado métodos para comparar, sea de forma artesanal, creando algún método propio o utilizando alguna librería existente. En este artículo se explica cómo comparar dos objetos en typescript con JSON patch (librería fast-json-patch).

Operadores de comparación

En typescript/javascript seguramente apreciarás las diferencias entre un “==” y un “===” y entre “!=” y “!==” sabiendo cuándo usarlos, y si no, te invito a que lo descubras sea en w3schools.com ó developer.mozilla.org por ponerte unos ejemplos. 

No obstante, los objetos con los que nos movemos en la vida real no suelen ser simples, más bien lo contrario, aunque en este artículo utilizaremos uno sencillo.

Comparar objetos

Para el ejemplo tendremos objetos que cumplen una interfaz siguiendo un modelo simple:

export interface IModel {
    id: number;
    name: string;
    age: number;
}

Si lo hacemos de forma artesanal, crearíamos por ejemplo un método llamado “equals” para esa comparación devolviendo un booleano, siendo verdadero si son iguales y falso en caso contrario comparando cada propiedad de cada objeto.

public equals(source: IModel, target: IModel): boolean {
    return  source.id === target.id &&
            source.name === target.name &&
            source.age === target.age
  } 

Como puedes ver esta forma de comparar tiene sus desventajas como por ejemplo si se añade una nueva propiedad al modelo, se tendría que refactorizar.

Podríamos mejorarlo para obtener las “keys” del objeto y luego recorrerlas en ambos objetos para comparar el valor de cada una. Podría funcionar, pero quizás este método se complicaría si el objeto es más complejo (contiene arrays, otros objetos, etc.) con lo que perderíamos un tiempo valioso para ir modificando este método.

Incluso podríamos utilizar JSON.stringify para hacerlo:

public equals<T>(source: T, target: T): boolean {
   return JSON.stringify(source) === JSON.stringify(target);
  }

Fast-json-patch

Hay muchísimas librerías para realizar comparaciones, pero aquí utilizaremos “fast-json-patch”.

Pero ¿Qué es el JSON-PATCH? Puedes leer el RFC6902 para tener una idea de lo que hace, en abstracto:

JSON Patch defines a JSON document structure for expressing a sequence of operations to apply to a JavaScript Object Notation (JSON) document; it is suitable for use with the HTTP PATCH method.
The «application/json-patch+json» media type is used to identify such patch documents.

https://tools.ietf.org/html/rfc6902

O dicho de otro modo: «JSON-Patch es un formato estándar que te permite actualizar un documento JSON enviando los cambios en lugar de todo el documento. JSON Patch funciona con el verbo (método) HTTP PATCH y la programación de estilo REST».

El caso es que a parte de obtener las diferencias entre objetos para enviar un “http patch”, esta librería tiene un método “compare” que facilita nuestro objetivo, quedando nuestro método de comparación en un simple wrapper:

import { Injectable } from '@angular/core';
import { compare, Operation } from 'fast-json-patch';
 
@Injectable({
  providedIn: 'root'
})
export class ComparerService {
 
  public equals<T>(source: T, target: T): boolean {
    const patch: Array<Operation> = compare(source, target);
    return patch.length === 0;
  }
 
}

Como en todas las librerías externas o terceros, delegamos la funcionalidad, con sus pros y contras. Nos beneficiamos en la delegación de la comparación y también podríamos utilizar el resto de su funcionalidad pero por contra, podría contener algún bug, problemas de seguridad, etc.

Esta es pues, otra manera de comparar. ¿Qué te ha parecido?

Puedes descargar el código del artículo en GitHub