11

I'm struggling in using moment.js library inside an Angular 2 Typescript app. Even after reading the answer to this question I can't get it to work.

This is what I did so far:

  • I installed moment.js using npm, so I can find the library under node_modules/moment/moment.js
  • I configured System.js to retrieve moment library:

    System.config({
        packages: {
          app: {
            format: 'register',
            defaultExtension: 'js'
          },
          moment: {
            main: 'moment.js',
            type: 'cjs',
            defaultExtension: 'js'
          }
        },
        map: {
          moment: 'node_modules/moment'
        }
    });
    
  • I installed typescript typings with typings install moment-node --ambient --save and typings install moment --ambient --save, so I can see the correct typings inside typings/main/ambient/moment-node and typings/main/ambient/moment

Now, if in my code I use import * as moment from 'moment'; typescript compilation run smooth and I can see the correct suggestion inside Atom editor (if I start with moment(). I can see year(), month(), etc.). However if I run my code inside the browser, it gives an error saying that 'moment is not a function' (debugging I can see that moment is an object with lots of methods).

If I write import moment from 'moment'; the code in the browser runs fine, however typescript compilation fails with 'module moment has no default export' and I can't get any suggestion from Atom while writing code.

What am I doing wrong? What's the correct way to import moment.js (and any non typescript library) inside an Angular 2 typescript application?

2
  • Try import moment from 'moment'; Commented Feb 7, 2016 at 14:25
  • Thanks for your reply! However, as I said in my answer, if I write import moment from 'moment'; typescript compilation fails and I can't get any suggestion from my IDE when using moment(). Commented Feb 7, 2016 at 14:49

5 Answers 5

5

As pointed out further down moment ships with its own typings now. And @angular/cli have changed aswell. Updated my answer to reflect this.

npm i --save moment

import * as moment from 'moment';

export class SomeClass implements OnInit {

  date: moment.Moment;

  ngOnInit() {
    this.date = moment();
  }

}

is all that is needed with @angular/cli.

Below is my old outdated answer.

With angular-cli: So you get Intellisense in VsCode

edit --> angular-cli-build.js

module.exports = function(defaults) {
  return new Angular2App(defaults, {
    vendorNpmFiles: [
      ...

      'moment/min/**', // add this line

      ...
    ]
  });
};

edit --> system-config.ts

const map: any = {
  moment: 'vendor/moment/min/moment.min.js' // add this line
};

In your component:

import * as moment from 'moment';

...
// example of usage
dates: moment.Moment[] = [];

ngOnInit() {
  let date = moment();
  date.add(2, 'days');
  this.dates.push(date);
}
Sign up to request clarification or add additional context in comments.

Comments

4
import * as moment_ from 'moment';
const moment:moment.MomentStatic = (<any>moment_)['default'] || moment_;

3 Comments

Great! This works nicely, thanks! I'm just wondering if there is some way to make the import nicer. I mean: if the moment.js typescript definitions were different, there would be a way to just write moment.default()? If moment.js main file was different, there would be a way to write just moment()? The problem I found with moment.js is tied more to its typescript definition files or to the way it is written?
This is not right. It works but it is ugly and confusing. The TypeScript compiler supports SystemJS with flags such as allowSyntheticDefaultImports.
This works at runtime, but does not compile within Visual Studio.
1

Also I found this: Install Moment.js using NPM:

npm install moment

Add it to your SystemJS configuration:

map: {
  'angular2': 'node_modules/angular2',
  'rxjs': 'node_modules/rxjs',
  'moment': 'node_modules/moment/moment'
}

You also need the interface: tsd install moment --save and then add:

/// <reference path="typings/moment/moment.d.ts" />
import * as moment from 'moment';

1 Comment

Monent ships with its own .d.ts file now. Also tsd is deprecated.
1

From your index.html add

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

In your component use:

declare var moment: any;
...

this.startDate = moment().subtract(15, 'days').format('DD-MM-YYYY');
this.endDate = moment().format('DD-MM-YYYY');

Comments

0

When you import a module using namespace syntax to gather the exports onto a single object, as in import * as moment from 'moment', you are not importing the actually moment object which the module exports, but rather all of its members. You are losing the call signature. To resolve this, in a SystemJS + TypeScript project, specify either a value of "system" for module or a value of true for allowSyntheticDefaultImports, passing these to the TypeScript compiler, preferably via a tsconfig.json file. Then import moment like so

import moment from 'moment';

and everything will work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.