How to instruct JSON.stringify() to custom serialize Date types?

Viewed 367
class MyClass {
  myString: string;
  myDate: Date;
}

function foo() {
  const myClassArray: MyClass[] = ....
  return JSON.stringify(myClassArray); // or expressApp.status(200).json(myClassArray);
}

foo will retun a json string with myDate a string following the ISO standard of YYYY-MM-DDThh:mm:ssZ.

I'd like to be able to customize how JSON.stringify() is serializing myDate.

I'm not stuck to JSON.stringify() to achieve what I want, although I prefer it since express.json() is using it behind the scene. In case this is not possible, is there a serialization library that will help me achieve what I want? Maybe a library that implements a decorator pattern? or maybe a more native solution?

1 Answers

You can use the replacer argument and pass in a function. There's probably a cleaner way to do this but this is a quick example:

const data = [{
    date: new Date(),
    id: 1
  },
  {
    date: new Date(),
    id: 2
  }
]


const a = JSON.stringify(data)
const b = JSON.stringify(data, replacer('date'))

function replacer(target) {
  return function(key, value) {
    if (key == target) {
      const month = new Date(value).getMonth()
      return `Date month: ${month}`
    }
    return value
  }
}

// [{"date":"2020-03-20T19:13:11.594Z","id":1},{"date":"2020-03-20T19:13:11.594Z","id":2}]
console.log(a)

// [{"date":"Date month: 2","id":1},{"date":"Date month: 2","id":2}]
console.log(b)

Edit

My TypeScript decorator kung fu isn't the strongest so if anyone has any suggestions feel free to point out improvements.

As a decorator:

@transformDate
class MyClass {
  date: Date;
  id: number;

  constructor(date, id) {
    this.date = date;
    this.id = id;
  }
}

function transformDate(target: any) {
  const formatted = new Intl.DateTimeFormat("en", {
    year: "numeric",
    month: "short",
    day: "2-digit"
  }).format(this.date);

  target.prototype.toJSON = function() {
    return {
      ...this,
      date: formatted
    };
  };

  return target;
}

const data = [new MyClass(new Date(), 1), new MyClass(new Date(), 2)];

// [{"date":"Mar 20, 2020","id":1},{"date":"Mar 20, 2020","id":2}]
console.log(JSON.stringify(data));

Related