267

I tried to use it with typescript bindings:

npm install moment --save
typings install moment --ambient -- save

test.ts:

import {moment} from 'moment/moment';

And without:

npm install moment --save

test.ts:

var moment = require('moment/moment');

But when I call moment.format(), I get an error. Should be simple, can anybody provide a command line/import combination that would work?

SnareChops
  • 13,175
  • 9
  • 69
  • 91
Sergey Aldoukhov
  • 22,316
  • 18
  • 72
  • 99
  • 1
    share your error please – basarat Feb 03 '16 at 00:04
  • 1
    If I install moment.d.ts and use import, I get compile error ERROR in .../typings/browser/ambient/moment/moment.d.ts (9,21): error TS2503: Cannot find namespace 'moment'. And if I don't install typings and use require, I get Uncaught TypeError: moment.format is not a function – Sergey Aldoukhov Feb 03 '16 at 00:13
  • There are far too many old answer here. Please look here: https://github.com/angular/angular-cli/wiki/3rd-party-libs#adding-momentjs-library-to-your-project – Didia Aug 14 '16 at 02:16
  • 3
    Hinrich's answer worked for me with ng4 (as of June 2017) https://stackoverflow.com/a/43257938/1554495 – tenderloin Jun 06 '17 at 07:34
  • SergeyAldoukhov is this still the best answer? surely @Hinrich's is? – jenson-button-event Sep 06 '17 at 12:03
  • Perfect on angular 7 and moment 2.24.0 – Natan Mar 30 '19 at 18:53
  • For angular 12 I have used https://stackoverflow.com/questions/49256040/a-namespace-style-import-cannot-be-called-or-constructed-and-will-cause-a-failu – Sudarshan May 09 '22 at 12:24

22 Answers22

589

Update April 2017:

As of version 2.13.0, Moment includes a typescript definition file. https://momentjs.com/docs/#/use-it/typescript/

Just install it with npm, in your console type

npm install --save moment

And then in your Angular app, import is as easy as this:

import * as moment from 'moment';

That's it, you get full Typescript support!

Bonus edit: To type a variable or property as Moment in Typescript you can do this e.g.:

let myMoment: moment.Moment = moment("someDate");
Hinrich
  • 13,485
  • 7
  • 43
  • 66
103

moment is a third party global resource. The moment object lives on window in the browser. Therefor it is not correct to import it in your angular2 application. Instead include the <script> tag in your html that will load the moment.js file.

To make TypeScript happy you can add

declare var moment: any;

at the top of your files where you use it to stop the compilation errors, or you can use

///<reference path="./path/to/moment.d.ts" />

or use tsd to install the moment.d.ts file which TypeScript might find on it's own.

Example

import {Component} from 'angular2/core';
declare var moment: any;

@Component({
    selector: 'example',
    template: '<h1>Today is {{today}}</h1>'
})
export class ExampleComponent{
    today: string = moment().format('D MMM YYYY');
}

Just be sure to add the script tag in your html or moment won't exist.

<script src="node_modules/moment/moment.js" />

Module loading moment

First you would need to setup a module loader such as System.js to load the moment commonjs files

System.config({
    ...
    packages: {
        moment: {
            map: 'node_modules/moment/moment.js',
            type: 'cjs',
            defaultExtension: 'js'
        }
    }
});

Then to import moment into the file where needed use

import * as moment from 'moment';

or

import moment = require('moment');

EDIT:

There are also options with some bundlers such as Webpack or SystemJS builder or Browserify that will keep moment off of the window object. For more information on these, please visit their respective websites for instruction.

SnareChops
  • 13,175
  • 9
  • 69
  • 91
  • 3
    That is possible, but is very lengthy as you would need to have a module loader such as `System` load in the commonjs node version of moment and then you would be able to reference it with `import * as moment from 'moment';` or `import moment = require('moment');` which for all intents and purposes are identical, but do have some subtle differences in typescript. – SnareChops Feb 03 '16 at 00:32
  • @SnareChops `typings install moment --ambient -- save` doesn't `typings` pull down the definition file and create the reference to `///`? I am having the same error when running `npm run tsc` – Shawn Northrop Feb 26 '16 at 08:59
  • This is misleading; there's nothing wrong with `import`ing moment. – Stiggler Mar 29 '16 at 16:44
  • @Stiggler I agree that there is noting wrong with importing moment as a first class `import` though it would require either a bundling system, or a change in the library. `import`ing won't work out of the box. This is the out-of-the box solution. – SnareChops Mar 29 '16 at 23:30
  • 2
    This answer is incomplete because you have to use Typings to manage the moment definition. Also, it doesn't need to import anything. Please, see [my answer bellow](http://stackoverflow.com/a/38664689/1814934). – Bernardo Pacheco Jul 29 '16 at 17:51
  • @BernardoPacheco Agreed. Your answer below shows the global usage case best, and saleksandras' answer shows the most updated way to use moment as a "module". – SnareChops Jul 31 '16 at 14:41
  • 8
    This answer is misleading, the fact that moment is a global variable does not mean you "have" to load it as a script tag. You can, and should, bundle it in a vendor file if you are using some sort of bundler (Webpack). You can also workaround the global assignment if you use webpack and a proper loader. – Shlomi Assaf Sep 27 '16 at 09:11
  • @ShlomiAssaf Added a comment at the bottom of the answer to acknowledge that there are other options. I was simply showing the solution for the option that the OP had chosen. – SnareChops Sep 28 '16 at 02:58
51

The following worked for me.

First, install the type definitions for moment.

typings install moment --save

(Note: NOT --ambient)

Then, to work around the lack of a proper export:

import * as moment from 'moment';
Stiggler
  • 2,800
  • 20
  • 21
  • 2
    I had to do `import moment from "moment";` instead to make it work. – Aetherix Apr 14 '16 at 20:46
  • 3
    This answer is incomplete because you don't need to import anything. Please, see [my answer bellow](http://stackoverflow.com/a/38664689/1814934). – Bernardo Pacheco Jul 29 '16 at 17:54
  • 1
    Also every iteration of ionic 2 beta / angular 2 rc seemed to bring a new way of importing things so you may have to try a few of these suggestions even though a one point they were once the most up to date answer – discodane Aug 18 '16 at 18:39
  • `import * as moment from 'moment';` is the key. – nima Jan 13 '17 at 08:36
  • I'm having Unable to find "moment" ("npm") in the registry. whenI try to install definitions, help please – Sebastián Rojas Jun 12 '17 at 16:39
29

I would go with following:

npm install moment --save

To your systemjs.config.js file's map array add:

'moment': 'node_modules/moment'

to packages array add:

'moment': { defaultExtension: 'js' }

In your component.ts use: import * as moment from 'moment/moment';

and that's it. You can use from your component's class:

today: string = moment().format('D MMM YYYY');

Aleksandras
  • 595
  • 6
  • 6
25

We're using modules now,

try import {MomentModule} from 'angular2-moment/moment.module';

after npm install angular2-moment

http://ngmodules.org/modules/angular2-moment

Sangwin Gawande
  • 7,658
  • 8
  • 48
  • 66
Falcon78
  • 706
  • 6
  • 6
  • 76
    This is insufficient, because this only installs pipes. Apparently, you cannot work with Moment dates in your modules this way. – ntaso Oct 12 '16 at 14:45
  • 1
    would love some tips on how to use angular2-moment filters in the component class – trickpatty Dec 07 '16 at 00:03
  • 3
    this should be: import { MomentModule } from 'angular2-moment/moment.module'; – yasser Feb 13 '17 at 23:22
  • 1
    This should not be the chosen answer any more. Take a look at @Hinrich 's answer. `npm install moment --save`, `npm install @types/moment --save` https://stackoverflow.com/questions/35166168/how-to-use-moment-js-library-in-angular-2-typescript-app/43257938#43257938 – jamesjansson May 22 '18 at 11:40
  • instead of installing a wrapper it should be like `import * as moment from 'moment';` – M. Atif Riaz Sep 17 '18 at 13:16
24

To use it in a Typescript project you will need to install moment:

npm install moment --save

After installing moment, you can use it in any .ts file after importing it:

import * as moment from "moment";

Shahzad
  • 473
  • 1
  • 5
  • 12
  • 1
    Note** @types/moment@2.13.0: This is a stub types definition for Moment (https://github.com/moment/moment). Moment provides its own type definitions, so you don't need @types/moment installed! – Winnemucca Jan 23 '17 at 08:58
  • 1
    Great! Here the official reference: https://momentjs.com/docs/#/use-it/typescript/ – Andrea Mar 11 '17 at 17:24
23

For Angular 7+ (Also Supports 8, 9, 10, 11):

1: Install moment by command npm install moment --save

2: Do not add anything in the app.module.ts

3: Just add import statement in top of your component or any other file like this: import * as moment from 'moment';

4: Now you can use moment anywhere in your code. Just like:

myDate = moment(someDate).format('MM/DD/YYYY HH:mm');

Rahmat Ali
  • 1,430
  • 2
  • 17
  • 29
  • I had to import like this: ```import * as moment_ from 'moment'; const moment = moment_;``` Otherwise I was getting `Error: Cannot call a namespace ('moment') ` – Snook Apr 12 '19 at 13:55
  • Very odd to listen. `moment_` is just a literal name. It can be anything, I think... – Rahmat Ali Apr 12 '19 at 16:34
  • 5
    Just be aware that `import * as moment from 'moment';` increase the size of the bundle by ~500kb. There is a good article explaining the problem with a solution https://medium.jonasbandi.net/angular-cli-and-moment-js-a-recipe-for-disaster-and-how-to-fix-it-163a79180173 – Kosmonaft Sep 03 '19 at 04:46
15

--- Update 11/01/2017

Typings is now deprecated and it was replaced by npm @types. From now on getting type declarations will require no tools apart from npm. To use Moment you won't need to install the type definitions through @types because Moment already provides its own type definitions.

So, it reduces to just 3 steps:

1 - Install moment which includes the type definitions:

npm install moment --save

2 - Add the script tag in your HTML file:

<script src="node_modules/moment/moment.js" />

3 - Now you can just use it. Period.

today: string = moment().format('D MMM YYYY');

--- Original answer

This can be done in just 3 steps:

1 - Install moment definition - *.d.ts file:

typings install --save --global dt~moment dt~moment-node

2 - Add the script tag in your HTML file:

<script src="node_modules/moment/moment.js" />

3 - Now you can just use it. Period.

today: string = moment().format('D MMM YYYY');
Bernardo Pacheco
  • 1,445
  • 1
  • 14
  • 23
  • I'm having trouble with the typings version that is available at dt. It is using an old version of moment that doesn't have the new methods I want to use. If I do as recommended by them (http://momentjs.com/docs/#/use-it/system-js/) the application compiles, but doesn't load in the browser. I'm almost reaching a dead end... – Fabricio Aug 22 '16 at 17:14
  • I couldn't get the script tag to work with angular cli. Makes more sense than importing though – Winnemucca Jan 23 '17 at 10:11
  • @Bernardo I tried following your steps and installed moment.js. After `declare var moment;` However, typings isn't working for me. After typing `moment().` no intellisense. I guess I am missing a few steps here. – Shyamal Parikh Jan 25 '17 at 12:50
  • Pretty sure this doesn't work, how does web pack know to include this with in the build node modules? – johnny 5 Apr 16 '17 at 17:02
9

with ng CLI

> npm install moment --save

in app.module

import * as moment from 'moment';

providers: [{ provide: 'moment', useValue: moment }]

in component

constructor(@Inject('moment') private moment)

this way you import moment once

UPDATE Angular => 5

{
   provide: 'moment', useFactory: (): any => moment
}

For me works in prod with aot and also with universal

I dont like using any but using moment.Moment I got

Error   Typescript  Type 'typeof moment' is not assignable to type 'Moment'. Property 'format' is missing in type 'typeof moment'.
Sangwin Gawande
  • 7,658
  • 8
  • 48
  • 66
Whisher
  • 31,320
  • 32
  • 120
  • 201
  • I get `Parameter 'moment' implicitly has an 'any' type` error. – Azimuth Nov 08 '17 at 08:56
  • Does this work for you in prod mode? It was working fine in dev mode, but when I run my app in prod mode it fails. My app has lazy loaded modules too (just in case that matters). moment ends up being null. – jbgarr Dec 08 '17 at 00:05
  • @jbgarr I've tried in a lazy module like constructor( @Inject('moment') private moment) { console.log('date', moment()); } with no problems – Whisher Dec 08 '17 at 18:34
8

The angular2-moment library has pipes like {{myDate | amTimeAgo}} to use in .html files.

Those same pipes can also be accessed as Typescript functions within a component class (.ts) file. First install the library as instructed:

npm install --save angular2-moment

In the node_modules/angular2-moment will now be ".pipe.d.ts" files like calendar.pipe.d.ts, date-format.pipe.d.ts and many more.

Each of those contains the Typescript function name for the equivalent pipe, for example, DateFormatPipe() is the function for amDateFormatPipe.

To use DateFormatPipe in your project, import and add it to your global providers in app.module.ts:

import { DateFormatPipe } from "angular2-moment";
.....
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, ...., DateFormatPipe]

Then in any component where you want to use the function, import it on top, inject into the constructor and use:

import { DateFormatPipe } from "angular2-moment";
....
constructor(.......,  public dfp: DateFormatPipe) {
    let raw = new Date(2015, 1, 12);
    this.formattedDate = dfp.transform(raw, 'D MMM YYYY');
}

To use any of the functions follow this process. It would be nice if there was one way to gain access to all the functions, but none of the above solutions worked for me.

royappa
  • 663
  • 1
  • 9
  • 20
  • This is awesome thanks! Everywhere for angular2 moment shows you how to use it on template only. Your very helpful post showed me how to use it to manipulate the value before I output it to the template. – Andrew Howard Apr 28 '17 at 16:14
  • @royappa I see some using the Pipes module and some using just moment to access it in Typescript. I understand you're saying you can use the Pipes version in Typescript but what would the harm be in installing both? – Jacques Jul 27 '18 at 07:30
6

for angular2 RC5 this worked for me...

first install moment via npm

npm install moment --save

Then import moment in the component that you want to use it

import * as moment from 'moment';

lastly configure moment in systemjs.config.js "map" and "packages"

// map tells the System loader where to look for things
  var map = {
  ....
  'moment':                     'node_modules/moment'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    ...
    'moment':                       { main:'moment', defaultExtension: 'js'}
  };
Arni Gudjonsson
  • 544
  • 9
  • 23
5

In addition to SnareChop's answer, I had to change the typings file for momentjs.

In moment-node.d.ts I replaced:

export = moment;

with

export default moment;
jevenson
  • 164
  • 3
  • 5
5

If you're okay adding more third-party packages, I used the angular2-moment library. Installation was pretty straightforward, and you should follow the latest instructions on the README. I also installed typings as a result of this.

Worked like a charm for me, and barely added any code to get it working.

wli
  • 726
  • 5
  • 5
5

Not sure if this is still an issue for people, however... Using SystemJS and MomentJS as library, this solved it for me

/*
 * Import Custom Components
 */
import * as moment from 'moment/moment'; // please use path to moment.js file, extension is set in system.config

// under systemjs, moment is actually exported as the default export, so we account for that
const momentConstructor: (value?: any) => moment.Moment = (<any>moment).default || moment;

Works fine from there for me.

Astrid Karsten
  • 121
  • 1
  • 2
  • 4
5

My own version of using Moment in Angular

npm i moment --save

import * as _moment from 'moment';

...

moment: _moment.Moment = _moment();

constructor() { }

ngOnInit() {

    const unix = this.moment.format('X');
    console.log(unix);    

}

First import moment as _moment, then declare moment variable with type _moment.Moment with an initial value of _moment().

Plain import of moment wont give you any auto completion but if you will declare moment with type Moment interface from _moment namespace from 'moment' package initialized with moment namespace invoked _moment() gives you auto completion of moment's api's.

I think this is the most angular way of using moment without using @types typings or angular providers, if you're looking auto completion for vanilla javascript libraries like moment.

flyingpluto7
  • 1,079
  • 18
  • 20
4

Moment.js now supports TypeScript in v2.14.1.

See: https://github.com/moment/moment/pull/3280

sivabudh
  • 31,807
  • 63
  • 162
  • 228
3

Try adding "allowSyntheticDefaultImports": true to your tsconfig.json.

What does the flag do?

This basically tells the TypeScript compiler that it's okay to use an ES6 import statement, i. e.

import * as moment from 'moment/moment';

on a CommonJS module like Moment.js which doesn't declare a default export. The flag only affects type checking, not the generated code.

It is necessary if you use SystemJS as your module loader. The flag will be automatically turned on if you tell your TS compiler that you use SystemJS:

"module": "system"

This will also remove any errors thrown by IDEs if they are configured to make use of the tsconfig.json.

Mark Langer
  • 1,064
  • 1
  • 9
  • 14
3

For ANGULAR CLI users

Using external libraries is in the documentation here:

https://github.com/angular/angular-cli/wiki/stories-third-party-lib

Simply install your library via

npm install lib-name --save

and import it in your code. If the library does not include typings, you can install them using:

npm install lib-name --save

npm install @types/lib-name --save-dev

Then open src/tsconfig.app.json and add it to the types array:

"types":[ "lib-name" ]

If the library you added typings for is only to be used on your e2e tests, instead use e2e/tsconfig.e2e.json. The same goes for unit tests and src/tsconfig.spec.json.

If the library doesn't have typings available at @types/, you can still use it by manually adding typings for it:

First, create a typings.d.ts file in your src/ folder.

This file will be automatically included as global type definition. Then, in src/typings.d.ts, add the following code:

declare module 'typeless-package';

Finally, in the component or file that uses the library, add the following code:

import * as typelessPackage from 'typeless-package'; typelessPackage.method();

Done. Note: you might need or find useful to define more typings for the library that you're trying to use.

Som
  • 460
  • 1
  • 5
  • 11
  • Checkout this article if you need step-by-step instructions. https://medium.com/@jek.bao.choo/steps-to-add-moment-js-to-angular-cli-f9ab28e48bf0 – wag0325 Jun 06 '18 at 19:00
2

The following worked for me:

typings install dt~moment-node --save --global

The moment-node does not exist in typings repository. You need to redirect to Definitely Typed in order to make it work using the prefix dt.

stvnwrgs
  • 137
  • 10
2

for angular2 with systemjs and jspm had to do:

import * as moment_ from 'moment';
export const moment =  moment_["default"];

var a = moment.now();
var b = moment().format('dddd');
var c = moment().startOf('day').fromNow();
born2net
  • 24,129
  • 22
  • 65
  • 104
1

I followed advice to allow allowSyntheticDefaultImports (since there is no export from moment to use for me), using System. Then I followed someone's advice to use:

import moment from 'moment';

With moment being mapped in my system.js config. The other import statements wouldn't work for me, for some reason

Paul Jerome Bordallo
  • 1,362
  • 10
  • 11
1

With systemjs what I did is, inside my systemjs.config I added map for moment

map: {
   .....,
   'moment': 'node_modules/moment/moment.js',
   .....
}

And then you can easily import moment just by doing

import * as moment from 'moment'
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299