web-dev-qa-db-ja.com

moment()。add()はリテラル値でのみ機能します

TypeScriptでMoment.jsを使用しています(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'.

ここで何が悪いのですか?

21
rocklobster

非推奨の逆オーバーロードadd(unit: unitOfTime.DurationConstructor, amount: number|string)はあいまいさを生じます。

これを修正するには、unitsのタイプをDurationConstructorではなくstringとして定義します。

let units: moment.unitOfTime.DurationConstructor = 'month';
moment().add(1, units);

もう1つのオプションは、constの代わりにletを使用することです。そのため、リテラルタイプが推論されます。

const units = 'month';
moment().add(1, units);
23
Aleksey L.

受け入れられた回答の別のオプションは、引数の型キャストです。実際には違いはありません。この回答をオプションとして含めると考えただけです。さらに簡潔にするために、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 )
3
Alex Spera

addの宣言は2つあります

  1. add(amount?: DurationInputArg1, unit?: DurationInputArg2): Moment;
  2. 非推奨add(unit: unitOfTime.DurationConstructor, amount: number|string)

TypeScriptがオーバーロードに一致する必要がある場合、最も近い型を取得しようとします。 _units:string_を渡そうとしたときに、最も近い一致_number|string_は2番目のオーバーロードです。これは、-任意の文字列がこの宣言に一致するためです。 _'qwe'_、またはstringタイプの_'rty'_、ただし_DurationArg2_ではない最初の宣言の2番目のパラメーターとして期待されています。

moment.add(1,'months)を呼び出すと、最初の宣言が使用されます。これは、_1_を最初のシグネチャの最初の引数の型にキャストできますが、2番目の型にはキャストできないためです。

したがって、この問題を修正するには、正確に何を使用したいかを言う必要があります。

例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. 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()
    }
  }
_
2
Nikita

私の場合の問題は、minsを使用していたことです。 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

2
kontinuity

この回答は、問題の原因としてdeprecated reverse syntax of add, subtract, etc functions in momentを指定する以前のすべての回答に基づいています。

これらのメソッドはすべてこれを究極のスーパークラスとして持っているので、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がエラーとしてマークされていることです。ユニットを修飾するときに修正されました。

1
HankCa

この問題は、モーメントライブラリ内の追加、減算などの関数の非推奨の逆構文が原因で発生します。以下は抜粋です。

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));

TypeScriptでのexpiryTimeの定義:

interface ExpiryTimeDef {
value: number,
unit: string
}
0
rahuljain1311

タイプ定義をletからconstに変更します

const units = 'month';
moment().add(1, units);

これは私のために働く。