如何在带有 SystemJS 的 TypeScript 中使用 momentjs?

How to use momentjs in TypeScript with SystemJS?

我的项目设置包括 'jspm' 库工具和 'tsd' 打字工具。

安装 moment 的 TypeScript d.ts 文件(these)后,我找不到加载和实际使用 moment 实例的方法。

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

我收到“TypeError:moment 不是函数

定义的结构与 lodash 相同,工作正常,所以我不知道可能是什么原因。

有人能帮忙吗?

有点不清楚你是想把moment用于客户端开发还是服务器端(例如node.js)。但是,如果你的情况是前端,那么我可以很轻松地使用 moment:

1) 我刚刚将文件添加到我的项目中:

2) 写了一个简单的测试代码:

window.onload = () =>
{
    var timestamp: number = 111111111111111;
    var momentResult: moment.Moment = moment(timestamp);
    alert(momentResult.toISOString());
};

我的项目构建正常,我在浏览器中看到了测试警报。

刚刚在我的项目中完成。它是 angular,但我认为这并不重要,可能会让您走上正确的道路。很简单:

import MomentStatic = moment.MomentStatic;

class HelpdeskTicketController {
  constructor(private moment: MomentStatic) { // angulars dependency injection, you will have some global probably
    let d = this.moment(new Date()); // works
    console.log(d.add(2, 'hours').format()); // works
  }

  ...

我假设 moment 是使用

安装的
jspm install moment

这应该会在您 config.js 的地图部分添加一个条目。

...
"moment": "npm:moment@2.10.6",
...

这样您就可以通过

访问您的js文件中的时刻
import moment from 'moment';

console.log(moment().format('dddd, MMMM Do YYYY, h:mm:ss a'));

导入时 * as moment 导入模块命名空间。所以时刻将是一个对象,其属性是模块导出。这样默认导出就不会作为 moment 导入,而是作为 moment.default 导入。 所以像

moment.default().format('dddd, MMMM Do YYYY, h:mm:ss a')

可能在您的代码中确实有效,但不是它的预期使用方式。

我做了以下事情:

我安装了momentdefinition file如下:

tsd install moment --save

然后我创建了main.ts:

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

import moment = require("moment");
moment(new Date());

而我运行:

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

main.js 看起来像这样:

// 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());
        }
    }
});

我的 TypeScript 版本是 1.6.2。

这是我发现的:

Momentjs 导出一个function(即_moment = utils_hooks__hooksutils_hooks__hooks是一个函数,很清楚。

如果你在我上面标为PLACE XY的地方下一个断点,你可以看到moment_1是一个对象(!)而不是一个函数。相关行:1, 2

综上所述,问题与TypeScript无关。问题是 systemjs 不保留 momentjs 导出函数的信息。 Systemjs 只是从模块中复制导出对象的属性(函数也是 JavaScript 中的对象)。我想你应该在 systemjs 存储库中提交一个问题,看看他们是否认为它是一个错误(或一个功能 :))。

这适用于 Angular 2 但不应特定于它。您基本上只是告诉系统加载程序在哪里可以找到 moment.min.js.

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'}
};

在您的模块中:

import moment from 'moment';

或(编辑 2016 年 10 月 13 日):

import * as moment from 'moment';

一些评论者在上面发布了 import * 语法,我在升级后也不得不切换到那个语法(不知道为什么)。

从 2.13 版开始,moment 包括 Typescript 类型。无需再使用 tsd(或 typings)。

systemjs.config.js 文件中,只需添加以下内容:

  var map = {
    // (...)
    moment: 'node_modules/moment',      
  };

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

并且在模块中:

import moment = require('moment')

在我的打字稿文件中,当我使用

import moment from 'moment';

它说找不到模块 'moment'。我已经将 moment 安装为 npm 包并且它被正确引用但是由于 moment.d.ts 将 moment 导出为命名空间而不是模块,如下所示,我无法引用它。

export = moment; 

所以如果我把它改成

declare module 'moment' {
    export default moment;
}

导入工作完美。我在这里做错了什么?

我很难让它工作,因为由于代理限制我无法使用 npm(因此不得不手动安装库)。如果将 moment 和 definitelytyped 文件的版本安装在项目中的适当位置,您可以通过一些摆弄来使它工作。

关于使用 moment 配置打字稿,有一个有用的说明 here on the moment.js website 。对我的案例有帮助的关键方面是在我的 tsconfig.json 文件的 compilerOptions 部分添加以下内容:

"allowSyntheticDefaultImports": true

对于我的东西,我将 Webpack 与 VS 2015(更新 3)一起使用。因此,在为 package.json 和 webpack.config.vendor.js 文件添加代码后,我只需要在组件的最顶部调用 import moment = require('moment') (TypeScript,Angular 2).