I'm using Moment.js in TypeScript (under Angular 2 if that matters). When I use the add() method with literal values as arguments, it works fine:
moment().add(1, 'month');
However, if I try to replace the units with a string, it fails:
let units:string = 'month';
moment().add(1, units);
with this error:
Argument of type '1' is not assignable to parameter of type 'DurationConstructor'.
What am I doing wrong here?
The add function is used to add date and time to the moment object and the subtract function subtract date and time from the moment object. const moment = require('moment'); let now = moment(); console.
Try moment('2020-03-30'). add(1, 'months') and then compare with moment('2020-03-31'). add(1, 'months') .
To add hours to a parsed moment date with JavaScript, we can use the add method. to add 5 hours to the moment object parsed from myDate . We call add with 5 and 'hours' to add 5 hours. And then we call format with a format string to return the datetime stored in the moment object.
The moment object in Moment.js is mutable. This means that operations like add, subtract, or set change the original moment object. As you can see, adding one week mutated a.
Because of the variability of duration in day math, Moment's API does not officially support adding or subtracting decimal values for days and larger. Moment.js will accept decimal values and do its best to handle them by rounding to the nearest whole number.
To print out the value of a Moment, use .format (), .toString () or .toISOString (). To retrieve a native Date object from Moment, use .toDate (). This function returns a properly shifted date for interaction with third party APIs. Moment.js has a very flexible and advanced parser that allows a huge range of functionality.
Using literal types with union types (used to compose types) you could define a type that represents an enumeration of literal values. For example, we can define the type Weather.
Deprecated reverse overload add(unit: unitOfTime.DurationConstructor, amount: number|string)
creates ambiguity.
You can fix this by defining type of units
to be DurationConstructor
instead of string
:
let units: moment.unitOfTime.DurationConstructor = 'month';
moment().add(1, units);
Another option is just to use const
instead of let
, so literal type will be inferred:
const units = 'month';
moment().add(1, units);
Another option to the accepted answer is typecasting in the argument. There's really no difference, just figured I'd include this answer as an option. Also unitOfTime can be imported from moment as a module if you want some more brevity.
import { unitOfTime } from 'moment';
import * as moment from 'moment';
option = {val: 30, unit: 'm'}
moment().add( this.querySince.val, <unitOfTime.DurationConstructor>this.querySince.unit )
Unfortunately, none of the above answers worked with me! But this only made the charm! :D
const startTime = moment().subtract(this.time.amount as moment.DurationInputArg1, this.time.unit as moment.DurationInputArg2);
There are two declarations of add
add(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
add(unit: unitOfTime.DurationConstructor, amount: number|string)
When typescript need to match overloads it tries to take closest type. When you've tried to pass units:string
, closest match number|string
is second overload, because any string will match to this declaration, f.e. 'qwe'
, or 'rty'
of type string
, but not DurationArg2
which is expected as second parameter in first declaration.
When you call moment.add(1,'months)
it will use first declaration, because it is possible to cast 1
to type of the first argument in first signature, but not in the second.
So to fix this issue and similar, you should say what you exactly want to use.
Example 1. First signature will be used
import * as moment from 'moment'
calculateRangeFromEnd(end: Date, unitsAmount: moment.DurationInputArg1, unitsMeasureMoment: moment.DurationInputArg2): IDateRange {
return {
endDate: end,
startDate: moment(end).subtract(unitsAmount, unitsMeasureMoment).toDate()
}
}
Example 2. Second signature will be used
import * as moment from 'moment'
calculateRangeFromEnd(end: Date, unitsAmount: number | string, unitsMeasureMoment: moment.unitOfTimes.DurationConstructor): IDateRange {
return {
endDate: end,
startDate: moment(end).subtract(unitsMeasureMoment, unitsAmount).toDate()
}
}
The problem in my case was that I was using mins
. The type def for DurationConstructor is
namespace unitOfTime {
type Base = (
"year" | "years" | "y" |
"month" | "months" | "M" |
"week" | "weeks" | "w" |
"day" | "days" | "d" |
"hour" | "hours" | "h" |
"minute" | "minutes" | "m" |
"second" | "seconds" | "s" |
"millisecond" | "milliseconds" | "ms"
);
So this works out of the box:
refTime.clone().subtract(15, 'minute')
-k
This answer is building on all the previous answers that specify deprecated reverse syntax of add, subtract, etc functions in moment
as the cause of the problem.
I cast the DurationInputArg2 field to unitOfTime.Base
since all these methods have this as the ultimate superclass and so it means for add, subtract, startOf, endOf
I just need to remember as Base
:
import Base = moment.unitOfTime.Base
theMoment.subtract(amount, unitString as Base)
theMoment.startOf(unitString as Base)
The confusing part for most people is that the amount
is marked as the error. Fixed when one qualifies the units.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With