怎样使用typescript导入moment.js?

116

我正努力学习 TypeScript。虽然我不认为这很重要,但我在这个演示中使用的是 VSCode。

我有一个 package.json 文件,其中包含以下内容:

{
  "devDependencies": {
    "gulp": "^3.9.1",
    "jspm": "^0.16.33",
    "typescript": "^1.8.10"
  },
  "jspm": {
    "moment": "npm:moment@^2.12.0"
  }
}

那么我有一个TypeScript类 main.js ,代码如下:

import moment from 'moment';
export class Main {
}

我的gulpfile.js看起来像这样:

var gulp = require('gulp');
var typescript = require('gulp-tsb');
var compilerOptions = {
                        "rootDir": "src/",
                        "sourceMap": true,
                        "target": "es5",
                        "module": "amd",
                        "declaration": false,
                        "noImplicitAny": false,
                        "noResolve": true,
                        "removeComments": true,
                        "noLib": false,
                        "emitDecoratorMetadata": true,
                        "experimentalDecorators": true
                      };
var typescriptCompiler = typescript.create(compilerOptions);
gulp.task('build', function() {
  return gulp.src('/src')
    .pipe(typescriptCompiler())
    .pipe(gulp.dest('/dest'));
});

当我运行 gulp build 时,出现以下信息:"../main.ts(1,25): Cannot find module 'moment'."

如果我使用import moment = require('moment');,那么 jspm 就会正常工作,并在运行应用程序时引入该模块,但我仍然收到构建错误。 我还尝试了:

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

然而,问题没有得到改善,反而变得更糟了。现在,我在构建时遇到了上述错误以及以下错误:"../typings/browser/ambient/moment/index.d.ts(9,21): Cannot find namespace 'moment'."

如果我进入typings提供的文件,在文件底部添加以下内容:

declare module "moment" { export = moment; }

我可以处理第二个错误,但是我仍然需要 require 语句才能让 moment 在我的 main.ts 文件中工作,并且仍然得到第一个编译错误。

我是否需要为 moment 创建自己的 .d.ts 文件,还是我只是缺少某些设置?


1
为了帮助遇到这个问题的人,我在此添加更新:import moment, { Moment } from 'moment'; 可以让你使用 const x = moment();const x: Moment = moment(); - ryuu9187
这些解决方案都没有起作用,我已经转移到这里 - https://github.com/date-fns/date-fns - chrismarx
7个回答

146

更新

显然,moment现在提供自己的类型定义(根据sivabudh的说法至少从2.14.1开始),因此您完全不需要使用typings@types

import * as moment from 'moment'应该会加载npm包中提供的类型定义。

尽管如此,在moment/pull/3319#issuecomment-263752265中提到,moment团队似乎在维护这些定义时存在一些问题(他们仍在寻找维护者)。


您需要安装moment typings,但不要使用--ambient标志。

然后使用import * as moment from 'moment'引入它。


1
说实话,我不会。通常情况下,你可以使用--ambient标志来处理typings/DefinitelyTyped中的所有TypeScript定义,但moment的定义有一些奇怪的结构,文件下载也不正确。如果你查看定义文件moment.d.ts,它只包含一个对于 Node 版本的引用,但这个引用并没有在下载时解析出来(可能值得提一个问题)。 - Aides
显然,已经有一个与此问题相关的链接:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/8388 - peinearydevelopment
1
我使用以下代码使其工作: import * as moment from 'moment/moment' 因为它作为node-modules文件夹中的子文件夹安装。 - user441058
1
我正在使用webpack和moment版本2.17.1,但仍然无法让它起作用。我尝试了以下方法:import * as moment from 'moment'; 和 import * as moment from 'moment/moment'; 但都不起作用! - Mohy Eldeen
虽然这样做可以工作,但它不会使树摇变得不可能吗?这样不会包含比我需要的更多吗? - adamdport
显示剩余6条评论

72

在TS中,您需要分别导入函数moment()和类Moment

我在typescript文档这里找到了一条注释。

/*~请注意,ES6模块无法直接导出可调用的函数
*~应该使用CommonJS风格导入此文件:
*~import x = require('someLibrary');

因此,将moment js导入typescript的代码实际上如下所示:

import { Moment } from 'moment'
....
let moment = require('moment');
...
interface SomeTime {
  aMoment: Moment,
}
...
fn() {
  ...
  someTime.aMoment = moment(...);
  ...
}

1
好的回答,因为它展示了类型和函数之间的区别。谢谢! - Jelle den Burger
找不到名称'require'。 - Coded Container
5
现在可以使用 import * as moment from 'moment';,然后使用 moment.Moment 来进行类型定义。 - meteor
对我有效的方法是:import moment = require('moment'); - Telmo Pimentel Mota
实际上,您也可以直接从名称空间moment使用moment.Moment接口。 - HalfWebDev
在2020年,我正在开发一个与vue.js和node/ts.ed一起使用的共享库,这是唯一对我有效的解决方案。尝试了其他方法半天都没用。import { Moment } from 'moment'; let moment = require('moment'); - GeekyMonkey

21

不确定这个问题何时改变,但是在最新版本的typescript中,只需要使用import moment from 'moment';,其他一切都应该正常工作。

更新:

看起来moment最近修复了他们的导入。至少在2.24.0及以上,你将需要使用import * as moment from 'moment';


9
import * as moment from 'moment' 在 TypeScript 中无法使用,但是 import moment from 'moment' 可以。 - Stuart McIntyre
它正在工作,但我得到的是GMT 0的时间,但我需要本地时间,这不起作用。我也尝试了moment().utc().format(),但它返回相同的结果。 - kbhaskar
@kbhaskar 截至最新版本的moment,他们已经修复了导入问题。请查看更新后的答案。 - NSjonas
1
我认为这就是全部了。我需要在配置文件中添加esModuleInterop并将其设置为true,这是我从这篇答案中得到的。谢谢。 - Mark Birbeck

16

通过 typings

Moment.js v2.14.1 现已支持 TypeScript。

查看:https://github.com/moment/moment/pull/3280


直接引用

可能不是最好的方法,但这是一种粗暴的方式,并且对我有效。

  1. 只需下载实际的 moment.js 文件并将其包含在您的项目中即可。
  2. 例如,我的项目看起来像这样:

$ tree . ├── main.js ├── main.js.map ├── main.ts └── moment.js

  1. 以下是示例源代码:

```

import * as moment from 'moment';

class HelloWorld {
    public hello(input:string):string {
        if (input === '') {
            return "Hello, World!";
        }
        else {
            return "Hello, " + input + "!";
        }
    }
}

let h = new HelloWorld();
console.log(moment().format('YYYY-MM-DD HH:mm:ss'));
  1. 只需使用node运行main.js即可。

是的,我确认这就是正确的答案。非常好用。 - Capy
当我尝试使用npm i @types/moment时,我收到了一个错误:TypeScript错误:src\app.ts(1,1):error TS7038:命名空间样式的导入不能被调用或构造,并且会在运行时导致失败。在tsc -v 2.7.2上。 - GONeale

8

我刚刚注意到我点赞并评论的答案有歧义。以下是确切适用于我的内容。我当前使用的Moment版本是2.26.0和TS版本是3.8.3

代码如下:

import moment from 'moment';

在 TS 配置文件中:

{
  "compilerOptions": {
    "esModuleInterop": true,
    ...
  }
}

我正在构建同时支持CommonJS和EMS的项目,因此这个配置文件被导入到其他配置文件中。

灵感来自于这个答案,它与使用Express有关。尽管如此,我认为将其添加在这里是值得的,以帮助任何搜索与Moment.js相关的内容,而不是更一般的内容。


然后您可以像平常一样使用 moment(),而不是 moment.default() - xinthose

5

ES6语法:

1. 安装moment

npm install --save moment

2. 在你的typescript文件中导入"moment"

import moment from 'moment';

2
这不是在TypeScript中导入模块的正确方式。请考虑更新您的答案。请参考此链接以确认:https://basarat.gitbook.io/typescript/project/modules/external-modules - Efe Ariaroo

3

仍然有问题?尝试卸载 @types/moment

因此,我从 package.json 文件中移除了 @types/moment 包,并使用以下命令使其工作:

import * as moment from 'moment'

较新版本的moment不需要@types/moment包,因为类型已经包含在内。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接