Repository: iamkun/dayjs
File: src/plugin/duration/index.js (JavaScript)

Code before:
  milliseconds() { return this.get('milliseconds') }
  asMilliseconds() { return this.as('milliseconds') }
  seconds() { return this.get('seconds') }
  asSeconds() { return this.as('seconds') }
  minutes() { return this.get('minutes') }
  asMinutes() { return this.as('minutes') }
  hours() { return this.get('hours') }
  asHours() { return this.as('hours') }
  days() { return this.get('days') }
  asDays() { return this.as('days') }
  weeks() { return this.get('weeks') }
  asWeeks() { return this.as('weeks') }
  months() { return this.get('months') }
  asMonths() { return this.as('months') }
  years() { return this.get('years') }
  asYears() { return this.as('years') }
}

const addDuration = (date, duration) =>
  date.add(duration.years(), 'year')
    .add(duration.months(), 'month')
    .add(duration.days(), 'day')
    .add(duration.hours(), 'hour')
    .add(duration.minutes(), 'minute')
    .add(duration.seconds(), 'second')
    .add(duration.milliseconds(), 'millisecond')

const subtractDuration = (date, duration) =>
  date.subtract(duration.years(), 'year')
    .subtract(duration.months(), 'month')
    .subtract(duration.days(), 'day')
    .subtract(duration.hours(), 'hour')
    .subtract(duration.minutes(), 'minute')
    .subtract(duration.seconds(), 'second')
    .subtract(duration.milliseconds(), 'millisecond')

export default (option, Dayjs, dayjs) => {
  $d = dayjs
  $u = dayjs().$utils()
  dayjs.duration = function (input, unit) {
    const $l = dayjs.locale()
    return wrapper(input, { $l }, unit)
  }
  dayjs.isDuration = isDuration

  const oldAdd = Dayjs.prototype.add
  const oldSubtract = Dayjs.prototype.subtract

  Dayjs.prototype.add = function (value, unit) {
    if (isDuration(value)) {
      return addDuration(this, value)

Review comment (suggestion):
a little trick to minimize the code, pass the third argument to combine add and subtract together.
```
// manipulateDuration(this, value, 1)
// manipulateDuration(this, value, -1)

// e.g. .add(duration.months() * (-1), 'month')
```

also, one thing that confused me, is why adding `value.asMilliseconds()`  is not the correct result. 
It should be the real `ms` between the two dates.

Code after:
  milliseconds() { return this.get('milliseconds') }
  asMilliseconds() { return this.as('milliseconds') }
  seconds() { return this.get('seconds') }
  asSeconds() { return this.as('seconds') }
  minutes() { return this.get('minutes') }
  asMinutes() { return this.as('minutes') }
  hours() { return this.get('hours') }
  asHours() { return this.as('hours') }
  days() { return this.get('days') }
  asDays() { return this.as('days') }
  weeks() { return this.get('weeks') }
  asWeeks() { return this.as('weeks') }
  months() { return this.get('months') }
  asMonths() { return this.as('months') }
  years() { return this.get('years') }
  asYears() { return this.as('years') }
}

const manipulateDuration = (date, duration, k) =>
  date.add(duration.years() * k, 'y')
    .add(duration.months() * k, 'M')
    .add(duration.days() * k, 'd')
    .add(duration.hours() * k, 'h')
    .add(duration.minutes() * k, 'm')
    .add(duration.seconds() * k, 's')
    .add(duration.milliseconds() * k, 'ms')

export default (option, Dayjs, dayjs) => {
  $d = dayjs
  $u = dayjs().$utils()
  dayjs.duration = function (input, unit) {
    const $l = dayjs.locale()
    return wrapper(input, { $l }, unit)
  }
  dayjs.isDuration = isDuration

  const oldAdd = Dayjs.prototype.add
  const oldSubtract = Dayjs.prototype.subtract

  Dayjs.prototype.add = function (value, unit) {
    if (isDuration(value)) {
      return manipulateDuration(this, value, 1)
    }

    return oldAdd.bind(this)(value, unit)
  }

  Dayjs.prototype.subtract = function (value, unit) {
    if (isDuration(value)) {
      return manipulateDuration(this, value, -1)
    }