2015-10-07 8 views
16

Ich versuche MomentJs von Typoskript zu verwenden: je nachdem, welches Modul-System ich zum Erstellen von Typoskript, finde ich ein anderes Verhalten, wie ich MomentJs verwenden kann. Wenn Typoskript mit Commonjs alles wie erwartet funktioniert Kompilieren und ich kann nur momentJs Dokumentation folgen:Typescript-Modul-Systeme auf MomentJS Verhalten seltsam

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

Wenn ich „System“ als Typoskript Modulsystem, wenn ich „Moment“ Ich importiere ich dazu gezwungen

import moment = require("moment"); 
moment.default(new Date()); //this works 
moment(new Date()); //this doesn't work 

fand ich eine Abhilfe sie beide arbeiten unabhängig von Typoskript Modulsystem zu machen, verwendet

import m = require("moment") 
var moment : moment.MomentStatic; 
moment = (m as any).default || m; 

Ich mag das nicht, und ich würde gerne verstehen, warum es so verhält. Mache ich etwas falsch? Kann mir jemand erklären, was passiert?

+1

import Moment von 'Moment'; scheint zu funktionieren, obwohl der Compiler einen "hat keinen Standard-Export" -Fehler anzeigt (aber kompiliert sowieso). Siehe auch diese Diskussion: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181 – Arlo

+1

Auch dieser Blogbeitrag ist nützlich: http://www.jbrantly.com/es6-module-with- typescript-and-webpack – Arlo

+0

Für mich gibt es moment.default nicht, wie ich es importiere, also weiß ich eigentlich nicht, wie man eine Instanz eines Momentobjekts erstellt. Hat jemand eine aktualisierte Antwort darauf? –

Antwort

14

Dies geschieht, weil SystemJS moment automatisch in ein ES6-style-Modul konvertiert, indem es es in ein Modulobjekt einwickelt, während CommonJS nicht ist.

Wenn CommonJS zieht moment, erhalten wir die tatsächliche moment Funktion. Dies ist, was wir in JavaScript seit einer Weile tun, und es sollte sehr vertraut aussehen. Es ist, als ob Sie schrieb:

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

Wenn SystemJS zieht in moment, es nicht geben Sie den Moment Funktion. Es erstellt ein Objekt mit der Momentfunktion, die einer Eigenschaft mit dem Namen default zugewiesen ist. Es ist, als ob Sie geschrieben hätten:

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

Warum macht es das? Weil ein Modul eine Karte von einer oder mehreren Eigenschaften sein sollte, keine Funktion, laut ES6/TS. In ES6 ist die Konvention für massive externe Bibliotheken, die sich selbst exportierten, sich selbst unter der default Eigenschaft eines Modulobjekts zu exportieren (export default) (lesen Sie mehr here; in ES6/TypeScript können Sie Funktionen wie diese mit der kompakten Syntax import moment from "moment" importieren).

Sie machen nichts falsch, Sie müssen nur das Format Ihrer importierten Module auswählen und bei Ihrer Wahl bleiben. Wenn Sie sowohl CommonJS als auch SystemJS verwenden möchten, können Sie sie so konfigurieren, dass sie denselben Importstil verwenden. Eine Suche nach 'systemjs default import' führte mich zu this discussion Ihres Problems, in dem sie die --allowSyntheticDefaultImports Einstellung implementieren.

+1

Ausgezeichnet, danke für die detaillierte und klare Erklärung. Es lohnt sich das Kopfgeld! – ColinE

+1

--allowSyntheticDefaultImports ist in 1.8 implementiert, das jetzt in der Betaversion ist – nemenos

2

Moment war ein Schmerz in das Projekt zu ziehen, die ich bin zu arbeiten, aber am Ende haben wir es zu lösen mit diesem:

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

danke für Ihre Antwort, aber auch damit, systemjs als Modul-System zu verwenden, hier ist die Fehlermeldung: Uncaught (in Aussicht) TypeError: Moment ist keine Funktion. Das gleiche wie zuvor – nemenos

+1

Tut mir leid, es hat dir nicht geholfen ... Ich habe den systemjs Teil vermisst ... meine Lösung benutzt commonjs – Brocco

+0

@Brocco du könntest dein Projekt aufräumen, indem du entweder 'const moment: moment.MomentStatic = require (" moment "); 'oder' importieren * als Moment von "Moment" ' –

5

Ich habe folgendes:

I moment installiert definition file als folgt:

tsd install moment --save 

Dann main.ts I erstellt:

///<reference path="typings/moment/moment.d.ts" /> 

import moment = require("moment"); 
moment(new Date()); 

Und ich lief:

$ tsc --module system --target es5 main.ts # no error 
$ tsc --module commonjs --target es5 main.ts # no error 

main.js sieht wie folgt aus:

// 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()); 
     } 
    } 
}); 

Meine Typoskript Version ist 1.6.2.

Dies ist, was ich herausgefunden habe:

Momentjs ein function (dh _moment = utils_hooks__hooks und utils_hooks__hooks ist eine Funktion exportiert, das ist ganz klar ist,

Wenn Sie einen Haltepunkt an der ich als PLACE XY oben bezeichneten Stelle platzieren. Sie können sehen, dass moment_1 ein Objekt ist und keine Funktion Relevante Zeilen: 1, 2

TL; DR: (!). es zu schließen, ist das Problem hat nichts mit TypeScript zu tun. Das Problem ist, dass systemjs die Information, dass moments eine Funktion exportiert, nicht bewahrt. Systemjs kopiert einfach Eigenschaften des exportierten Objekts aus einem Modul (eine Funktion ist auch ein Objekt in JavaScript). Ich denke, Sie sollten ein Problem in systemjs Repository einreichen, um herauszufinden, ob sie es als einen Fehler (oder ein Feature :) betrachten).

+0

Fehler ist nicht zur Kompilierzeit, aber wenn Sie versuchen, es zu verwenden, scheint es, dass die Verwendung von System Sie ein zusätzliches Feld namens Standard verwendet zu finden. wenn Sie commonj verwenden s, moment.default ist undefined und Sie müssen Moment direkt verwenden – nemenos

+1

Danke, ich habe versucht, Ihr Problem zu debuggen, und ich habe meine Antwort entsprechend aktualisiert. HTH –

+0

Es werden keine Eigenschaften kopiert, sondern ein "Moment" in einem Modulobjekt. –

2

Hier ist, wie ich tat, mit System.js und Typoskript 1.7.5

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

Aber beachten Sie, dass ich utc() Methode verwenden. Ich kann moment() nicht verwenden, weil als mk. erklärt hat, wird dies von System.js in moment.default() konvertiert. Natürlich enthalten Typisierte Typings keine default Methode, um Kompilierungsfehler zu vermeiden, müsste man etwas wie moment["default"]() verwenden (ich weiß, hässlich).

Nächster Schritt musste ich folgendes System.js Config hinzuzufügen:

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

Danach, alles wie ein Charme.

0

Für meine system.config:

paths: { 
    'moment': 'node_modules/moment/moment.js' 
}, 
packages: { 
    app: { 
     format: 'register', 
     defaultExtension: 'js' 
    } 
} 

importieren momentjs in meiner Komponente entfernt ich das * die ich denke, behandelt den Code in den moment.js als mehrere Objekte einreichen.

Wechsel:

import * as moment from 'moment'; 

zu:

import moment from 'moment'; 
0

hatte ich

import * as moment from 'moment';

und verändert alles, was ich sollte gedacht

var date: moment = moment();

zu

var date: moment.Moment = moment();