Untitled

mail@pastecode.io avatar
unknown
typescript
5 months ago
2.6 kB
4
Indexable
type ChangeDetail<T> = {
  originalVal: T,
  currentVal: T
}

type Changes<T> = {
  [Key in keyof T]?: T[Key] extends object ? Changes<T[Key]> : ChangeDetail<T[Key]>
}

function compare<T extends object>(oldObj: T, newObj: T): Changes<T>{
  const result: Changes<T> = {};

  for(const key in {...oldObj, ...newObj}){
    const oldObjHasKey  = oldObj.hasOwnProperty(key)
    const newObjHasKey  = newObj.hasOwnProperty(key)
    const keyOfT = key as keyof T; // type specification

    if(oldObjHasKey && newObjHasKey){
      // old and new object has the same key
      const oldVal = oldObj[keyOfT]
      const newVal = newObj[keyOfT]

      if (oldVal !== newVal) {
        // Only show the difference fields
        if(oldVal !== null && newVal !== null && typeof oldVal === 'object' && typeof newVal === 'object'){
          // recursive call
          const nestedChanges = compare(oldVal, newVal);

          if(Object.keys(nestedChanges).length > 0){
            result[key as keyof T] = nestedChanges as Changes<T>[keyof T];
          }
        }
        else{
            result[keyOfT] = {
              originalVal: oldObj[keyOfT],
              currentVal: newObj[keyOfT]
            } as Changes<T>[keyof T]
          }
        }
   }else if(oldObjHasKey){
    // oldObject has the key that newObject doesn't
      result[keyOfT] = {
          originalVal: oldObj[keyOfT],
          currentVal: undefined
        } as Changes<T>[keyof T]
   }else if(newObjHasKey){
    // newObject has the key that oldObject doesn't
      result[keyOfT] = {
          originalVal: undefined,
          currentVal: newObj[keyOfT]
        } as Changes<T>[keyof T]
   }
          
  }

  return result
}

interface MyObject {
  name?: string;
  age?: number;
  email? :string;
  address?: {
    street?: string;
    city?: string;
    zipcode?: number,
    moreInfo?: {
        ward?: string,
        district?: string
    },
    description: {
        text: string,
        no: number
    }
  };
}

const oldData: MyObject = {
  name: "Long",
  email: "longnb6@haha.com",
  address: {
    street: "123 batrieu",
    city: "hanoi",
    zipcode: 10000,
    moreInfo: {
        ward: 'hangbo',
        district: 'hoankiem'
    },
     description: {
        text: '1',
        no: 2
    }
  }
};

const newData: MyObject = {
  age: 28,
  email: "dungnh6@haha.com",
  address: {
    street: "tran khanh tong",
    city: "hanoi",
      moreInfo: {
        ward: 'daimo',
        district: 'nam tu liem'
    },
     description: {
        text: '1',
        no: 2
    }
  }
};

const result = compare(oldData, newData);
console.log(result);
Leave a Comment