Moment(). add() работает только с литеральными значениями
Я использую Moment.js в TypeScript (при Angular 2, если это имеет значение). Когда я использую метод add() с литеральными значениями в качестве аргументов, он отлично работает:
moment().add(1, 'month');
Однако, если я попытаюсь заменить единицы на строку, это не сработает:
let units:string = 'month';
moment().add(1, units);
с этой ошибкой:
Argument of type '1' is not assignable to parameter of type 'DurationConstructor'.
Что я здесь делаю неправильно?
Ответы
Ответ 1
Устаревшее обратное add(unit: unitOfTime.DurationConstructor, amount: number|string)
перегрузки add(unit: unitOfTime.DurationConstructor, amount: number|string)
создает неоднозначность.
Вы можете исправить это, определив тип units
как DurationConstructor
вместо string
:
let units: moment.unitOfTime.DurationConstructor = 'month';
moment().add(1, units);
Другой вариант - просто использовать const
вместо let
, поэтому будет выведен буквенный тип:
const units = 'month';
moment().add(1, units);
Ответ 2
В моем случае проблема заключалась в том, что я использовал mins
. Тип def для DurationConstructor -
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"
);
Итак, это получается из коробки:
refTime.clone().subtract(15, 'minute')
-k
Ответ 3
Другой вариант принятого ответа - приведение типа в аргументе. Там действительно нет никакой разницы, просто решил, что я бы включил этот ответ в качестве опции. Кроме того, unitOfTime может быть импортирован мгновенно как модуль, если вы хотите немного краткости.
import { unitOfTime } from 'moment';
import * as moment from 'moment';
option = {val: 30, unit: 'm'}
moment().add( this.querySince.val, <unitOfTime.DurationConstructor>this.querySince.unit )
Ответ 4
Есть два объявления о add
-
add(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
- Устаревшее
add(unit: unitOfTime.DurationConstructor, amount: number|string)
Когда машинописный текст должен соответствовать перегрузкам, он пытается принять наиболее близкий тип. Когда вы попытались передать units:string
, номер ближайшего совпадения number|string
является второй перегрузкой, потому что любая строка будет соответствовать этому объявлению, например, 'qwe'
или 'rty'
типа string
, но не DurationArg2
который ожидается как второй параметр в первом объявлении.
Когда вы вызываете moment.add(1,'months)
он будет использовать первое объявление, потому что можно привести 1
к типу первого аргумента в первой сигнатуре, но не во второй.
Таким образом, чтобы исправить эту проблему и подобное, вы должны сказать, что именно вы хотите использовать.
Пример 1. Будет использована первая подпись
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()
}
}
Пример 2. Будет использоваться вторая подпись
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()
}
}
Ответ 5
Эта проблема вызвана устаревшим обратным синтаксисом функций add, subtract и etc в библиотеке минут. Ниже приведен фрагмент:
moment.d.ts
add(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
/**
* @deprecated reverse syntax
*/
add(unit: unitOfTime.DurationConstructor, amount: number|string): Moment;
В моем случае я хотел, чтобы единицы и значение оба были переменными, поэтому мне пришлось написать функцию для преобразования строки general
в приемлемые ( "часы", "минуты" и т.д.).
function convertToDuration (unit: string): Moment.unitOfTime.DurationConstructor {
if(unit == 'seconds' || unit == 'minutes' || unit == 'hours' || unit == 'days' || unit == 'weeks' || unit == 'months'){
return unit;
}
else // Default unit is hours
return 'hours';
}
Теперь для вызова этой функции:
const time = moment().add(expiryTime.value, convertToDuration(expiryTime.unit));
Определение expiryTime в TypeScript:
interface ExpiryTimeDef {
value: number,
unit: string
}
Ответ 6
Измените определение типа с let
на const
const units = 'month';
moment().add(1, units);
это работает для меня..
Ответ 7
Этот ответ основан на всех предыдущих ответах, deprecated reverse syntax of add, subtract, etc functions in moment
в качестве причины проблемы указан deprecated reverse syntax of add, subtract, etc functions in moment
. Д.
Я unitOfTime.Base
поле DurationInputArg2 к unitOfTime.Base
так как все эти методы имеют этот конечный суперкласс, и это означает, что для add, subtract, startOf, endOf
мне просто нужно помнить as Base
:
import Base = moment.unitOfTime.Base
theMoment.subtract(amount, unitString as Base)
theMoment.startOf(unitString as Base)
Запутывающая часть для большинства людей в том, что amount
помечена как ошибка. Исправлено, когда один квалифицирует юнитов