Typescript模块系统on momentJS行为异常

0wi1tuuw  于 2022-11-18  发布在  TypeScript
关注(0)|答案(9)|浏览(166)

我正在尝试使用momentJs从 typescript :根据我用来编译类型脚本的模块系统,我发现如何使用momentJs有不同的行为。当使用commonJs编译类型脚本时,一切都按预期工作,我只需遵循momentJs文档:

import moment = require("moment");
moment(new Date()); //this works

如果我用**“系统”**作为typescript模块系统当我导入“时刻”时我被迫做

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;

我不喜欢这样,我想知道为什么它会这样。我做错了什么吗?谁能给我解释一下发生了什么?

0ve6wy6x

0ve6wy6x1#

我通过更换

import moment from "moment";

import语句

import * as moment from "moment";

这个。

vxqlmq5t

vxqlmq5t2#

这是因为SystemJS通过将moment Package 在模块对象中自动将其转换为ES6样式的模块,而CommonJS则不是。
CommonJS拉入moment时,我们得到了实际的moment函数。这是我们在JavaScript中已经做了一段时间的事情,看起来应该很熟悉。就像你写的那样:

var moment = function moment() {/*implementation*/}

SystemJS拉入moment时,它不会给予你moment函数,而是创建一个对象,将moment函数赋给一个名为default的属性,就像你写的那样:

var moment = {
    default: function moment() {/*implementation*/}
}

为什么要这样做呢?因为根据ES6/TS,一个模块应该是一个或多个属性的Map,而不是一个函数。在ES6中,以前导出自己的大量外部库的约定是使用export default在模块对象的default属性下导出自己(在这里阅读更多内容;在ES6/TypeScript中,您可以使用紧凑的import moment from "moment"语法导入类似这样的函数)。
你没有做错什么,你只需要选择你导入模块的格式,并坚持你的选择。如果你想同时使用CommonJS和SystemJS,你可能会考虑配置它们使用相同的导入样式。搜索'systemjs default import'让我找到了你的问题的this discussion,其中它们实现了--allowSyntheticDefaultImports设置。

eoxn13cs

eoxn13cs3#

我执行了以下操作:
我安装了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导出一个函数(即_moment = utils_hooks__hooksutils_hooks__hooks是一个函数,这是相当清楚的。
如果你在上面PLACE XY的位置放置一个断点,你可以看到moment_1是一个对象(!)而不是一个函数。第1、2页

**TL;DR:**总结一下,这个问题与TypeScript无关。问题是systemjs没有保存momentjs导出函数的信息。Systemjs只是从模块中复制导出对象的属性(函数在JavaScript中也是一个对象)。我想你应该在systemjs仓库中提交一个问题,看看他们是否认为这是一个bug(或一个功能:)。

umuewwlo

umuewwlo4#

下面是我如何使用System.js和Typescript 1.7.5

import * as moment from "moment";
...
moment.utc(); // outputs 2015 (for now).

但请注意我使用的是utc()方法。我不能使用moment(),因为正如mk.解释的那样,它被System.js转换为moment.default()。当然,明确类型的类型不包含default方法,所以为了避免编译错误,需要使用类似moment["default"]()的方法(我知道,很难看)。
下一步,我需要将以下内容添加到System.js配置中:

System.config({
  paths: {
    'moment': 'node_modules/moment/moment.js'
  }
});

在这之后,一切都像一种魅力。

hm2xizp9

hm2xizp95#

Moment是一个痛苦的拉到项目,我正在工作,但我们最终解决了它使用这个:

import momentRef = require('moment');
var moment: moment.MomentStatic = momentRef;
vwoqyblh

vwoqyblh6#

对于我的系统配置:

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

pjngdqdw7#

我有
import * as moment from 'moment';
改变了我认为应该
var date: moment = moment();

var date: moment.Moment = moment();

dw1jzc5e

dw1jzc5e8#

如果您使用的是typescript,则默认导入(如import moment from "moment")的作用与const moment = require("moment").default相同。请参见https://www.typescriptlang.org/tsconfig#esModuleInterop

**TLDR;**在tsconfig.json中添加esModuleInterop: true

ghg1uchk

ghg1uchk9#

如果您使用的是TypeScript,import * as moment from 'moment可以正常工作,但是InSonarQube是严重错误,因为请显式导入所需的特定成员。

  • 根据清晰的代码就是更好的代码的原则,你应该显式地导入你想在模块中使用的东西。使用import * 导入模块中的所有东西,并冒着让维护人员感到困惑的风险。类似地,export * 来自“module”;导入然后再重新导出模块中的所有内容,这不仅会使维护人员感到困惑,还会使模块的用户感到困惑。*

相关问题