Модуль Typescript на момент JS ведет себя странно
Я пытаюсь использовать momentJs из машинописного текста: в зависимости от того, какую модульную систему я использую для компиляции машинописного текста, я нахожу другое поведение относительно того, как я могу использовать momentJ. При компиляции машинописи с помощью commonJs все работает как положено, и я могу просто следовать документации момента JJ:
import moment = require("moment");
moment(new Date()); //this works
Если я использую "систему" в качестве системного модуля, когда я импортирую "момент", я вынужден сделать
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;
Мне это не нравится, и я хотел бы понять, почему он так себя ведет. Я делаю что-то неправильно? Кто-нибудь может объяснить мне, что происходит?
9 ответов
Это происходит потому, что 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 вы можете импортировать такие функции, используя компактный import moment from "moment"
синтаксис).
Вы не делаете ничего плохого, вам просто нужно выбрать формат ваших импортированных модулей и придерживаться вашего выбора. Если вы хотите использовать как CommonJS, так и SystemJS, вы можете настроить их для использования одного и того же стиля импорта. Поиск 'systemjs default import' привел меня к обсуждению вашей проблемы, в котором они реализуют --allowSyntheticDefaultImports
установка.
Я решил проблему, заменив
import moment from "moment";
оператор импорта с
import * as moment from "moment";
это.
Я сделал следующее:
Я установил 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 не сохраняет информацию о том, что моментальный файл экспортирует функцию. Systemjs просто копирует свойства экспортируемого объекта из модуля (функция также является объектом в JavaScript). Я полагаю, вам следует зарегистрировать проблему в репозитории systemjs, чтобы узнать, считают ли они, что это ошибка (или фича:)).
Вот как я это сделал с System.js и Typescript 1.7.5
import * as moment from "moment";
...
moment.utc(); // outputs 2015 (for now).
Но обратите внимание, что я использую utc()
метод. Я не могу использовать moment()
потому что как тк. объяснил, это превращается в moment.default()
System.js. Причины Типизированных Типизированных Типов не содержат default
метод, поэтому, чтобы избежать ошибки компиляции, нужно использовать что-то вроде moment["default"]()
(Знаю, некрасиво).
Следующим шагом мне нужно было добавить следующее в конфигурацию System.js:
System.config({
paths: {
'moment': 'node_modules/moment/moment.js'
}
});
После этого все заработало как шарм.
Момент был трудным, чтобы втянуть в проект, над которым я работаю, но в итоге мы решили его с помощью этого:
import momentRef = require('moment');
var moment: moment.MomentStatic = momentRef;
Если вы используете машинописный текст, импорт по умолчанию, например
import moment from "moment"
действует так же, как
const moment = require("moment").default
. См. Https://www.typescriptlang.org/tsconfig#esModuleInterop
TL; DR; Добавить
esModuleInterop: true
в вашем tsconfig.json
Я имел
import * as moment from 'moment';
и изменил все, что я думал, должно быть
var date: moment = moment();
в
var date: moment.Moment = moment();
Для моего 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';
Если вы используете TypeScript,
По принципу, что более понятный код — лучший код, вы должны явно импортировать то, что хотите использовать в модуле. Использование import * импортирует все в модуль и рискует запутать сопровождающих. Аналогично, экспортируйте * из "модуля"; импортирует, а затем реэкспортирует все в модуле и рискует запутать не только сопровождающих, но и пользователей модуля.