Typescript модульные системы на момент JJ ведут себя странно
Я пытаюсь использовать momentJs из typescript:
в зависимости от того, какую модульную систему я использую для компиляции typescript, я нахожу другое поведение в отношении того, как я могу использовать momentJs.
При компиляции typescript с commonJs все работает так, как ожидалось, и я могу просто следить за документацией timeJs:
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
Я нашел обходное решение, чтобы заставить их работать независимо от используемой системы typescript
import m = require("moment")
var moment : moment.MomentStatic;
moment = (m as any).default || m;
Мне это не нравится, и я хотел бы понять, почему он ведет себя так. Я делаю что-то неправильно? Может ли кто-нибудь объяснить мне, что происходит?
Ответы
Ответ 1
Это происходит потому, что SystemJS автоматически преобразует moment
в модуль в стиле ES6, обернув его в объект модуля, а CommonJS - нет.
Когда CommonJS втягивается moment
, мы получаем фактическую функцию moment
. Это то, что мы делали в JavaScript на некоторое время, и должно выглядеть очень хорошо. Это как если бы вы написали:
var moment = function moment() {/*implementation*/}
Когда SystemJS тянет moment
, он не дает вам моментальную функцию. Он создает объект с функцией момента, присвоенной свойству с именем default
. Это как если бы вы написали:
var moment = {
default: function moment() {/*implementation*/}
}
Почему это так? Поскольку модуль должен быть отображением одного или нескольких свойств, а не функции, согласно ES6/TS. В ES6 соглашение для массивных внешних библиотек, которые ранее экспортировались, состоит в том, чтобы экспортировать себя в свойстве default
объекта модуля с помощью export default
(подробнее здесь; в ES6/ TypeScript вы можете импортировать такие функции, как это, используя синтаксис compact import moment from "moment"
).
Вы ничего не делаете неправильно, вам просто нужно выбрать формат ваших импортированных модулей и придерживаться вашего выбора. Если вы хотите использовать как CommonJS, так и SystemJS, вы можете изучить их настройку, чтобы использовать тот же стиль импорта. Поиск 'systemjs default import' привел меня к этой дискуссии вашей проблемы, в которой они реализуют настройку --allowSyntheticDefaultImports
.
Ответ 2
Я сделал следующее:
Я установил moment
следующим образом:
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__hooks
и utils_hooks__hooks
- это функция, которая достаточно понятна.
Если вы разместите точку останова в месте, обозначенном мной как PLACE XY
выше, вы увидите, что moment_1
является объектом (!), а не функцией. Соответствующие строки: 1, 2
TL; DR:. Для этого проблема не имеет ничего общего с TypeScript. Проблема в том, что systemjs не сохраняет информацию о том, что momentjs экспортирует функцию. Systemjs просто копирует свойства экспортируемого объекта из модуля (функция также является объектом в JavaScript). Я думаю, вы должны указать проблему в репозитории systemjs, чтобы узнать, считают ли они, что это ошибка (или функция:)).
Ответ 3
Момент был большой проблемой для проекта, над которым я работаю, но мы решили его решить, используя это:
import momentRef = require('moment');
var moment: moment.MomentStatic = momentRef;
Ответ 4
Вот как я это сделал с System.js и Typescript 1.7.5
import * as moment from "moment";
...
moment.utc(); // outputs 2015 (for now).
Но обратите внимание, что я использую метод utc()
. Я не могу использовать moment()
, потому что как mk. объяснил, что он преобразуется в moment.default()
с помощью System.js. Причина Определенно типизированные типизации не содержат метода default
, поэтому, чтобы избежать ошибки компиляции, нужно было бы использовать что-то вроде moment["default"]()
(я знаю, уродливо).
Следующий шаг, мне нужно добавить в конфигурацию System.js следующее:
System.config({
paths: {
'moment': 'node_modules/moment/moment.js'
}
});
После этого все работало как прелесть.
Ответ 5
Для моего system.config:
paths: {
'moment': 'node_modules/moment/moment.js'
},
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
Импорт импульсов в моем компоненте Я удалил *, который, как я думаю, обрабатывает код в файле moment.js как несколько объектов.
Изменить:
import * as moment from 'moment';
в
import moment from 'moment';
Ответ 6
У меня был
import * as moment from 'moment';
и изменил все, что я думал, должно быть
var date: moment = moment();
к
var date: moment.Moment = moment();