Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use momentjs in TypeScript with SystemJS?

My project's setup includes 'jspm' tool for libraries and 'tsd' tool for typings.

After installing moment's TypeScript d.ts file (these), I can't find a way to load and actually use a moment instance.

In my file (using SystemJS module loading)

/// <reference path="../../../typings/tsd.d.ts" />
import * as moment from "moment";
import * as _ from "lodash";
...
...
const now = (this.timestamp === 0) ? moment() : moment(this.timestamp);

I get a "TypeError: moment is not a function"

The definitions are structured the same as lodash, which works fine, so I don't know what might be the cause.

Can anyone help?

like image 212
Dror Weiss Avatar asked Nov 26 '15 12:11

Dror Weiss


People also ask

How do I import a moment in TypeScript?

To import moment. js with TypeScript, we can import the whole package with import . import * as moment from "moment"; to import the 'moment' module as moment .

How do you define a moment in TypeScript?

To use Moment. js with TypeScript, we can use the types provided by moment . import * as moment from "moment"; Then in the getDate method, we set the return type of it to moment.


4 Answers

I did the following:

I installed moment definition file as follows:

tsd install moment --save 

Then I created main.ts:

///<reference path="typings/moment/moment.d.ts" />  import moment = require("moment"); moment(new Date()); 

And I ran:

$ tsc --module system --target es5 main.ts # no error  $ tsc --module commonjs --target es5 main.ts # no error  

main.js looks like this:

// https://github.com/ModuleLoader/es6-module-loader/blob/v0.17.0/docs/system-register.md - this is the corresponding doc ///<reference path="typings/moment/moment.d.ts" /> System.register(["moment"], function(exports_1) {     var moment;     return {         setters:[             function (moment_1) {                 // You can place `debugger;` command to debug the issue                 // "PLACE XY"                 moment = moment_1;             }],         execute: function() {             moment(new Date());         }     } }); 

My TypeScript version is 1.6.2.

This is what I found out:

Momentjs exports a function (i.e. _moment = utils_hooks__hooks and utils_hooks__hooks is a function, that's quite clear.

If you place a breakpoint at the place I denoted as PLACE XY above, you can see that moment_1 is an object (!) and not a function. Relevant lines: 1, 2

To conclude it, the problem has nothing to do with TypeScript. The issue is that systemjs does not preserve the information that momentjs exports a function. Systemjs simply copy properties of the exported object from a module (a function is an object in JavaScript too). I guess you should file an issue in systemjs repository to find out if they consider it to be a bug (or a feature :)).

like image 172
Martin Vseticka Avatar answered Sep 28 '22 02:09

Martin Vseticka


Since version 2.13, moment includes Typescript typings. No need to use tsd (or typings) anymore.

In the systemjs.config.js file, just add the following:

  var map = {     // (...)     moment: 'node_modules/moment',         };    var packages = {     // (...)     moment: { main: 'moment.js', defaultExtension: 'js' },   }; 

And in the module:

import moment = require('moment') 
like image 36
Philippe Plantier Avatar answered Sep 28 '22 03:09

Philippe Plantier


I had immense trouble getting this to work, as I could not use npm due to proxy restrictions (therefore had to manually install the libraries). Provided the versions of moment and definitelytyped files are installed in appropriate locations in your project, you can get this to work with a bit of fiddling around.

There is a useful note here on the moment.js website on configuring typescript with moment. The key aspect which helped in my case was adding the following in the compilerOptions section of my tsconfig.json file:

"allowSyntheticDefaultImports": true
like image 37
RichL Avatar answered Sep 28 '22 02:09

RichL


This works with Angular 2 but shouldn't be specific to it. You're basically just telling the System loader where to find moment.min.js.

In system.config.js:

// map tells the System loader where to look for things
var map = {
  'app':                        'app', // 'dist',

  '@angular':                   'node_modules/@angular',
  'rxjs':                       'node_modules/rxjs',

  // tell system where to look for moment
  'moment':                     'node_modules/moment/min'
};

// packages tells the System loader how to load when no filename and/or no extension
var packages = {
  'app':                        { main: 'main.js',  defaultExtension: 'js' },
  'rxjs':                       { defaultExtension: 'js' },

  // tell system which file represents the script when you import
  'moment':                     { main: 'moment.min.js', defaultExtension: 'js'}
};

In your module:

import moment from 'moment';

OR (Edit 10/13/2016):

import * as moment from 'moment';

Some commenters have posted the import * syntax above and I had to switch to that as well after some upgrades (not sure why).

like image 29
Josh Werts Avatar answered Sep 28 '22 02:09

Josh Werts