momentJS 上的 Typescript 模块系统表现异常
Typescript module systems on momentJS behaving strangely
我正在尝试使用打字稿中的 momentJs:
根据我用来编译打字稿的模块系统,我发现了关于如何使用 momentJs 的不同行为。
当使用 commonJs 编译打字稿时,一切都按预期工作,我可以按照 momentJs 文档进行操作:
import moment = require("moment");
moment(new Date()); //this works
如果我在导入时使用 "system" 作为打字稿模块系统 "moment" 我被迫做
import moment = require("moment");
moment.default(new Date()); //this works
moment(new Date()); //this doesn't work
我找到了一种解决方法,无论使用何种打字稿模块系统,它们都能正常工作
import m = require("moment")
var moment : moment.MomentStatic;
moment = (m as any).default || m;
我不喜欢这样,我想了解为什么它会这样。难道我做错了什么?谁能给我解释一下这是怎么回事?
进入我正在从事的项目的那一刻是痛苦的,但我们最终用这个解决了它:
import momentRef = require('moment');
var moment: moment.MomentStatic = momentRef;
我做了以下事情:
我安装了moment
definition 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__hooks
和utils_hooks__hooks
是一个函数,很清楚。
如果你在我上面标为PLACE XY
的地方下一个断点,你可以看到moment_1
是一个对象(!)而不是一个函数。相关行:1, 2
TL;DR: 综上所述,问题与TypeScript无关。问题是 systemjs 不保留 momentjs 导出函数的信息。 Systemjs 只是从模块中复制导出对象的属性(函数也是 JavaScript 中的对象)。我想你应该在 systemjs 存储库中提交一个问题,看看他们是否认为它是一个错误(或一个功能 :))。
发生这种情况是因为 SystemJS 通过将其包装在模块对象中而自动将 moment
转换为 ES6 样式的模块,而 CommonJS 则不会。
当 CommonJS 引入 moment
时,我们得到了实际的 moment
函数。这是我们在 JavaScript 中已经做了一段时间的事情,看起来应该很熟悉。就好像你写了:
var moment = function moment() {/*implementation*/}
当 SystemJS 引入 moment
时,它不会给你 moment 函数。它创建一个对象,其矩函数分配给一个名为 default
的 属性。就好像你写了:
var moment = {
default: function moment() {/*implementation*/}
}
为什么要这样做?因为根据 ES6/TS,模块应该是一个或多个属性的映射,而不是函数。在 ES6 中,以前导出自身的大量外部库的约定是使用 export default
在模块对象的 default
属性 下导出自身(阅读更多 here;在 ES6/TypeScript,您可以使用紧凑的 import moment from "moment"
语法导入这样的函数。
您没有做错任何事,您只需要选择导入模块的格式,并坚持您的选择。如果你想同时使用 CommonJS 和 SystemJS,你可能会考虑将它们配置为使用相同的导入样式。搜索 'systemjs default import' 让我找到了你的问题的 this discussion,他们在其中实施了 --allowSyntheticDefaultImports
设置。
这是我使用 System.js 和 Typescript 1.7.5
的方式
import * as moment from "moment";
...
moment.utc(); // outputs 2015 (for now).
但请注意,我使用的是 utc()
方法。我不能使用 moment()
因为作为 mk。已经说明了,这个由System.js转换成moment.default()
。因为 Definitely Typed 类型不包含 default
方法,所以为了避免编译错误,需要使用类似 moment["default"]()
的东西(我知道,丑陋)。
下一步,我需要将以下内容添加到 System.js 配置中:
System.config({
paths: {
'moment': 'node_modules/moment/moment.js'
}
});
此后,一切如常。
我的 system.config:
paths: {
'moment': 'node_modules/moment/moment.js'
},
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
在我的组件中导入 momentjs 我删除了我认为将 moment.js 文件中的代码视为多个对象的 *。
变化:
import * as moment from 'moment';
至:
import moment from 'moment';
我有
import * as moment from 'moment';
并改变了我认为应该的一切
var date: moment = moment();
至
var date: moment.Moment = moment();
我通过替换
解决了这个问题
import moment from "moment";
导入语句
import * as moment from "moment";
这个。
如果您使用的是打字稿,则像 import moment from "moment"
这样的默认导入与 const moment = require("moment").default
的作用相同。看
https://www.typescriptlang.org/tsconfig#esModuleInterop
TLDR;
在您的 tsconfig.json
中添加 esModuleInterop: true
我正在尝试使用打字稿中的 momentJs: 根据我用来编译打字稿的模块系统,我发现了关于如何使用 momentJs 的不同行为。 当使用 commonJs 编译打字稿时,一切都按预期工作,我可以按照 momentJs 文档进行操作:
import moment = require("moment");
moment(new Date()); //this works
如果我在导入时使用 "system" 作为打字稿模块系统 "moment" 我被迫做
import moment = require("moment");
moment.default(new Date()); //this works
moment(new Date()); //this doesn't work
我找到了一种解决方法,无论使用何种打字稿模块系统,它们都能正常工作
import m = require("moment")
var moment : moment.MomentStatic;
moment = (m as any).default || m;
我不喜欢这样,我想了解为什么它会这样。难道我做错了什么?谁能给我解释一下这是怎么回事?
进入我正在从事的项目的那一刻是痛苦的,但我们最终用这个解决了它:
import momentRef = require('moment');
var moment: moment.MomentStatic = momentRef;
我做了以下事情:
我安装了moment
definition 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__hooks
和utils_hooks__hooks
是一个函数,很清楚。
如果你在我上面标为PLACE XY
的地方下一个断点,你可以看到moment_1
是一个对象(!)而不是一个函数。相关行:1, 2
TL;DR: 综上所述,问题与TypeScript无关。问题是 systemjs 不保留 momentjs 导出函数的信息。 Systemjs 只是从模块中复制导出对象的属性(函数也是 JavaScript 中的对象)。我想你应该在 systemjs 存储库中提交一个问题,看看他们是否认为它是一个错误(或一个功能 :))。
发生这种情况是因为 SystemJS 通过将其包装在模块对象中而自动将 moment
转换为 ES6 样式的模块,而 CommonJS 则不会。
当 CommonJS 引入 moment
时,我们得到了实际的 moment
函数。这是我们在 JavaScript 中已经做了一段时间的事情,看起来应该很熟悉。就好像你写了:
var moment = function moment() {/*implementation*/}
当 SystemJS 引入 moment
时,它不会给你 moment 函数。它创建一个对象,其矩函数分配给一个名为 default
的 属性。就好像你写了:
var moment = {
default: function moment() {/*implementation*/}
}
为什么要这样做?因为根据 ES6/TS,模块应该是一个或多个属性的映射,而不是函数。在 ES6 中,以前导出自身的大量外部库的约定是使用 export default
在模块对象的 default
属性 下导出自身(阅读更多 here;在 ES6/TypeScript,您可以使用紧凑的 import moment from "moment"
语法导入这样的函数。
您没有做错任何事,您只需要选择导入模块的格式,并坚持您的选择。如果你想同时使用 CommonJS 和 SystemJS,你可能会考虑将它们配置为使用相同的导入样式。搜索 'systemjs default import' 让我找到了你的问题的 this discussion,他们在其中实施了 --allowSyntheticDefaultImports
设置。
这是我使用 System.js 和 Typescript 1.7.5
的方式import * as moment from "moment";
...
moment.utc(); // outputs 2015 (for now).
但请注意,我使用的是 utc()
方法。我不能使用 moment()
因为作为 mk。已经说明了,这个由System.js转换成moment.default()
。因为 Definitely Typed 类型不包含 default
方法,所以为了避免编译错误,需要使用类似 moment["default"]()
的东西(我知道,丑陋)。
下一步,我需要将以下内容添加到 System.js 配置中:
System.config({
paths: {
'moment': 'node_modules/moment/moment.js'
}
});
此后,一切如常。
我的 system.config:
paths: {
'moment': 'node_modules/moment/moment.js'
},
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
在我的组件中导入 momentjs 我删除了我认为将 moment.js 文件中的代码视为多个对象的 *。
变化:
import * as moment from 'moment';
至:
import moment from 'moment';
我有
import * as moment from 'moment';
并改变了我认为应该的一切
var date: moment = moment();
至
var date: moment.Moment = moment();
我通过替换
解决了这个问题import moment from "moment";
导入语句
import * as moment from "moment";
这个。
如果您使用的是打字稿,则像 import moment from "moment"
这样的默认导入与 const moment = require("moment").default
的作用相同。看
https://www.typescriptlang.org/tsconfig#esModuleInterop
TLDR; 在您的 tsconfig.json
中添加esModuleInterop: true