ค้นหาเว็บไซต์

ระบบโมดูล Typescript บน momentJS ทำงานแปลกๆ


ฉันกำลังพยายามใช้ momentJs จาก typescript: ขึ้นอยู่กับว่าฉันใช้ระบบโมดูลแบบใดในการคอมไพล์ typescript ฉันจะพบพฤติกรรมที่แตกต่างกันเกี่ยวกับวิธีการใช้ momentJs เมื่อคอมไพล์ typescript ด้วย commonJs ทุกอย่างทำงานตามที่คาดไว้และฉันสามารถทำตามเอกสารของ momentJs ได้เลย:

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

ถ้าฉันใช้ "system" เป็นระบบโมดูล TypeScript เมื่อฉันนำเข้า "moment" ฉันถูกบังคับให้ต้องทำ

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

ฉันแก้ปัญหาโดยการเปลี่ยน

import moment from "moment";

คำสั่ง import พร้อมกับ

import * as moment from "moment";

นี่

คำตอบ #2

สิ่งนี้เกิดขึ้นเพราะ SystemJS กำลังแปลง moment ไปเป็นโมดูลสไตล์ ES6 โดยอัตโนมัติโดยห่อมันในวัตถุโมดูล ในขณะที่ CommonJS ไม่ได้ทำเช่นนั้น

เมื่อ CommonJS ดึง moment เข้ามา เราจะได้ฟังก์ชัน moment จริง ๆ ซึ่งนี่คือสิ่งที่เราทำใน JavaScript มาสักระยะหนึ่งแล้ว และมันควรจะดูคุ้นเคยมาก มันเหมือนกับว่าคุณเขียนว่า:

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

เมื่อ SystemJS ดึง moment เข้ามา มันจะไม่ให้คุณฟังก์ชัน moment โดยตรง มันจะสร้างอ็อบเจ็กต์ที่มีฟังก์ชัน 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

บทความที่เกี่ยวข้อง