Typescript: Erwägen Sie, den Zugriff auf UMD-Globals von Modulen aus zuzulassen

Erstellt am 5. Aug. 2016  ·  73Kommentare  ·  Quelle: microsoft/TypeScript

Das Feedback von # 7125 ist, dass einige Leute tatsächlich globale und importierte UMD-Bibliotheken mischen und abgleichen, was wir bei der Implementierung der Funktion nicht als wahrscheinliches Szenario angesehen haben.

Drei plausible Optionen:

  1. Tun Sie, was wir heute tun - schlecht, weil es keine gute Problemumgehung gibt
  2. Lassen Sie eine Syntax oder Konfiguration zu, dass "diese UMD global tatsächlich global verfügbar ist" - etwas komplex, aber machbar
  3. Ermöglichen Sie den Zugriff auf alle UMD-Globals unabhängig vom Kontext. Es fehlen Fehler, bei denen Benutzer vergessen, das UMD-Global in eine Datei zu importieren. Diese sind vermutlich etwas selten, aber es wäre dumm, sie zu verpassen

Klingt so, als würde es funktionieren, würde es aber wahrscheinlich nicht tun:

  1. Kennzeichnen Sie importierte UMD-Module als "für global nicht verfügbar" - schlecht, da UMD-Module während der Modulerweiterung in Deklarationsdateien importiert werden. Es wäre seltsam, wenn sich Importe aus Implementierungsdateien von Deklarationsdateien unterscheiden würden.

Ich bin der Einfachheit halber zu Option 3 geneigt, könnte aber Option 2 sehen, wenn es eine einigermaßen gute Syntax oder Konfiguration gibt, die wir an einer logischen Stelle verwenden könnten. Das Erkennen der Verwendung eines UMD-Global in einer TSLint-Regel wäre unkompliziert, wenn jemand dies tun möchte.

Ein Weg vorwärts wäre die Implementierung von Option 3, und wenn sich herausstellt, dass häufig der Fehler "Import vergessen" auftritt, fügen Sie eine tsconfig-Option globals: [] , die explizit angibt, welche UMD-Globals zulässig sind.

Add a Flag Committed Suggestion good first issue help wanted

Hilfreichster Kommentar

+1 dazu. Ich habe nur versucht, React mit SystemJS zu verwenden, und da React nicht sehr gut gebündelt ist, lade ich es einfach direkt aus dem CDN in ein Skript-Tag, und daher sind die React / ReactDOM-Objekte global verfügbar.

Ich schreibe Code als Module als Best Practice, aber dieser wird in einem Laufzeitskript gebündelt (Rollup), das beim Laden ausgeführt wird. Es ist ein Schmerz (und eine Lüge), import from reagieren / reagieren zu müssen und dann den Loader so zu konfigurieren, dass er sagt "nicht wirklich, das sind Globals" (ähnlich der Beispiel-WebPack-Konfiguration in https: / /www.typescriptlang.org/docs/handbook/react-&-webpack.html). Es wäre viel einfacher (und genauer), diese einfach als Globals in meinen Modulen verfügbar zu haben. Die Schritte, die ich versuchte, da sie intuitiv erschienen, waren:

  1. npm install --save-dev @types/react @types/react-dom
  2. In meiner tsconfig.json: "jsx": "react", "types": ["react", "react-dom"]
  3. In meinem Modul: export function MyComponent() { return <div>{"Hello, world"}</div>; }
  4. Ähnlich: ReactDOM.render(...)

Dies führt jedoch zu dem Fehler React refers to a UMD global, but the current file is a module. Consider adding an import instead .

Wenn dies nur funktionieren würde, wäre dies viel einfacher, als im Code vorzutäuschen, dass es sich um ein Modul handelt, und dann den Loader / Bundler so zu konfigurieren, dass dies nicht der Fall ist. (Oder alternativ habe ich es dazu gebracht, das zu tun, was ich erwartet hatte, indem ich eine Datei hinzugefügt habe, die Folgendes enthält. Jetzt können meine Module React & ReactDOM fehlerfrei als Globals verwenden, aber es ist irgendwie hässlich / hackig - obwohl es einen einfacheren Weg gibt, wie ich ' habe verpasst):

import * as ReactObj from "react";
import * as ReactDOMObj from "react-dom";

declare global {
    var React: typeof ReactObj;
    var ReactDOM: typeof ReactDOMObj;
}

Alle 73 Kommentare

Anstatt den Zugriff auf alle UMD-Globals unabhängig vom Kontext zuzulassen, wäre es nicht einfacher, den Zugriff auf das UMD-Global nur zuzulassen, wenn das UMD-Modul explizit über die Syntax ///<reference types=<>> "referenziert" (nicht importiert) wurde oder über die Konfiguration types in tsconfig.json?

Mit anderen Worten, warum nicht einfach zulassen, dass ///<reference types=<>> innerhalb eines Moduls verwendet wird?

Wenn wir sagten, dass /// <reference type="x" /> bedeutet, dass x global überall verfügbar ist, wird es häufig vorkommen, dass eine .d.ts-Datei irgendwo falsch auf Dinge verweist, die nicht wirklich global sind ( Ich kann Ihnen das sagen, weil ich den 2.0-Zweig von DefinitelyTyped gewartet habe und es ein äußerst häufiger Fehler ist.

Umgekehrt, wenn es nur in dieser Datei verfügbar ist, müssen Sie überall Referenzanweisungen kopieren und einfügen, was wirklich ärgerlich ist. Diese Anweisungen sind normalerweise idempotent, daher ist die Einführung eines dateispezifischen Verhaltens seltsam.

Aha. Wenn dies niemanden betrifft, ist es vielleicht besser, das aktuelle Verhalten beizubehalten. Ich muss nur ganz auf den Import von Dingen als Module umsteigen.

Edit: froh zu sehen, dass dies viele Menschen außer mir betrifft.

Die derzeitige Theorie besteht darin, die Leute nur zu bitten, auf Module zu migrieren oder nicht. Wenn andere Personen darauf stoßen, hinterlassen Sie bitte einen Kommentar mit genau den Bibliotheken, die Sie verwendet haben, damit wir weitere Untersuchungen durchführen können.

Ich benutze lodash, das nicht mit eigenen Eingaben geliefert wird. Ich habe auch eine Situation, in der es in meiner Laufzeitumgebung am einfachsten ist, relative Pfadimportanweisungen zu verwenden. Ich habe also eine Kombination aus Importanweisungen mit lokalen relativen Pfaden und Ordnerverwandten ('./foo' sowie 'N / bar').

Wenn ich die @types/lodash/index.d.ts manuell nach node_modules/lodash/ kopiere, kann ich die Dinge überprüfen lassen.

Bisher verwendete meine Problemumgehung ///<amd-dependency path='../lodash' name="_"> (und keine import -Anweisung). Mit dieser Kombination werden die @ types / lodash-Definitionen vom Compiler "global" angezeigt und haben immer noch den richtigen relativen Pfad ( ../lodash ) in der ausgegebenen JS.

Ich hoffe, dies ist ein Szenario, das diesem Problem nahe genug kommt.

Könntest Du das erläutern

Ich habe auch eine Situation, in der es in meiner Laufzeitumgebung am einfachsten ist, relative Pfadimportanweisungen zu verwenden.

und

Wenn ich die @types/lodash/index.d.ts manuell nach node_modules/lodash/ kopiere, kann ich die Dinge überprüfen lassen.

Bitte? Ich bin mit diesem Szenario nicht vertraut. Was ist der Zweck dieses Szenarios und warum ist es hilfreich?

Hallo Leute,

Ich bin in dem Prozess für eine Lösung von der Suche nach aktuellem @types/bluebird Erklärung Problem (bitte nicht verbringen Zeit , es zu lesen). Ich fand heraus, dass das Problem gelöst werden konnte, indem export as namespace Promise; zu .d.ts hinzugefügt wurde, aber dann stieß ich auf das Problem, das durch dieses Github-Problem beschrieben wurde.

Kurz gesagt, ich möchte, dass Folgendes funktioniert:

  1. git clone -b vanilla-es5-umd-restriction-problem https://github.com/d-ph/typescript-bluebird-as-global-promise.git
  2. cd typescript-bluebird-as-global-promise
  3. npm install
  4. Bearbeiten Sie node_modules/@types/bluebird/index.d.ts indem Sie export as namespace Promise; über der Zeile export = Bluebird; hinzufügen.
  5. npm run tsc

Aktuelles Ergebnis:
Ein paar 'Promise' refers to a UMD global, but the current file is a module. Consider adding an import instead. Fehler.

Erwartetes Ergebnis:
Kompilierung erfolgreich.

Dieses Problem ist besonders schwierig, da es durch die Verwendung von Promise sowohl im Entwicklercode als auch im Code von Drittanbietern (in diesem Fall RxJS) ausgelöst wird. Letzteres setzt voraus, dass Promise global ist (vom JS-Standard bereitgestellt) und daher niemals die Verwendung von zB import Promise from std; // (not that "std" is a thing) ändern wird.

Ich würde eine Möglichkeit sehr schätzen, UMD-Module sowohl als importierbare Module als auch als globale Module zu verwenden.

Vielen Dank.

----------------------------- Update

Am Ende habe ich dieses Problem anders gelöst (nämlich durch die Erweiterung der Schnittstellen um Promise und PromiseConstructor ).

Die Option "globals": [] tsconfig ist vorzuziehen, um sie überall sichtbar zu machen. Da die UMD-Deklaration zur Norm wird, ist die Wahrscheinlichkeit hoch, dass versehentlich vergessen wird, ein Modul zu importieren. Bitte denken Sie daran, das aktuelle Verhalten beizubehalten. Dies sollte ein Fehler sein.

Anekdotisch erinnere ich mich, als Moment ihre globale Variable window.moment in einer Punktveröffentlichung entfernte. Wir dachten, wir hätten es mit Bedacht überall importiert, aber wir hatten 5 Orte vergessen.

Natürlich wird ein UMD-Paket zur Laufzeit im globalen Bereich verfügbar sein, aber wann es verfügbar wird, hängt von der Reihenfolge ab, in der andere Module geladen werden.

+1 dazu. Ich habe nur versucht, React mit SystemJS zu verwenden, und da React nicht sehr gut gebündelt ist, lade ich es einfach direkt aus dem CDN in ein Skript-Tag, und daher sind die React / ReactDOM-Objekte global verfügbar.

Ich schreibe Code als Module als Best Practice, aber dieser wird in einem Laufzeitskript gebündelt (Rollup), das beim Laden ausgeführt wird. Es ist ein Schmerz (und eine Lüge), import from reagieren / reagieren zu müssen und dann den Loader so zu konfigurieren, dass er sagt "nicht wirklich, das sind Globals" (ähnlich der Beispiel-WebPack-Konfiguration in https: / /www.typescriptlang.org/docs/handbook/react-&-webpack.html). Es wäre viel einfacher (und genauer), diese einfach als Globals in meinen Modulen verfügbar zu haben. Die Schritte, die ich versuchte, da sie intuitiv erschienen, waren:

  1. npm install --save-dev @types/react @types/react-dom
  2. In meiner tsconfig.json: "jsx": "react", "types": ["react", "react-dom"]
  3. In meinem Modul: export function MyComponent() { return <div>{"Hello, world"}</div>; }
  4. Ähnlich: ReactDOM.render(...)

Dies führt jedoch zu dem Fehler React refers to a UMD global, but the current file is a module. Consider adding an import instead .

Wenn dies nur funktionieren würde, wäre dies viel einfacher, als im Code vorzutäuschen, dass es sich um ein Modul handelt, und dann den Loader / Bundler so zu konfigurieren, dass dies nicht der Fall ist. (Oder alternativ habe ich es dazu gebracht, das zu tun, was ich erwartet hatte, indem ich eine Datei hinzugefügt habe, die Folgendes enthält. Jetzt können meine Module React & ReactDOM fehlerfrei als Globals verwenden, aber es ist irgendwie hässlich / hackig - obwohl es einen einfacheren Weg gibt, wie ich ' habe verpasst):

import * as ReactObj from "react";
import * as ReactDOMObj from "react-dom";

declare global {
    var React: typeof ReactObj;
    var ReactDOM: typeof ReactDOMObj;
}

Ich stimme auch den Optionen drei plus Globals zu: [] Backup. Das scheint neuen und alten Benutzern ziemlich intuitiv zu sein und würde genau die Funktionalität bieten, die die Leute brauchen.

Ich bin kein Spezialist für den Code, daher kann ich nicht wirklich sagen, ob 2 vorzuziehen wäre oder nicht, aber ich denke, es wäre auch intuitiv, da die Konfiguration einfach ist.

Wenn ich Hilfe bei der Implementierung einer dieser Optionen suchen wollte, wohin sollte ich gehen?

Dies sollte wirklich hinter einer Flagge sein. Es ist eine massive Refactoring-Gefahr. Auch wenn das Flag standardmäßig true ist. Ich denke, dies muss im ursprünglichen Szenario weiter funktionieren, sonst verlieren wir den Hauptnutzen von UMD-Deklarationen.

Reagieren Sie nicht sehr gut

@ Billti kannst du das

Es ist ein Schmerz (und eine Lüge), import from reagieren / reagieren zu müssen und dann den Lader so zu konfigurieren, dass er sagt "nicht wirklich, das sind Globale".

Der einzige Grund, warum ich das im Tutorial geschrieben habe, ist, dass die Verwendung von externals die Bundle-Zeit verkürzt. Wenn Sie die globale Variable React ohne Import verwenden, können Sie später nicht einfach zu Modulen wechseln, wohingegen Importe Ihnen die Flexibilität bieten, beide Variablen mit Ihrem Loader zu verwenden.

In diesem Problem (https://github.com/rollup/rollup/issues/855) finden Sie ein Beispiel dafür, wie sie versuchen, die Bündelung zu optimieren, und welche Größen beobachtet werden. Tatsächlich habe ich in meinem Setup (mit Rollup) minimale Größenzuwächse bei der Bündelung von React festgestellt, daher würde ich es lieber nur von einem CDN aus bereitstellen. Für mich hat das folgende Vorteile:

a) Weniger Anfragen (und Bandbreite) an meine Site.
b) Weniger Zeit zum Bündeln in meiner Build-Kette.
c) Jedes Mal, wenn ich eine Änderung drücke, muss weniger Code auf den Client erneut heruntergeladen werden (da sich nur mein Code in dem Bundle befindet, das erneut heruntergeladen wird, und React sich noch unverändert im Client-Cache befindet - und somit 304 Sekunden erhält).

Wenn Sie in den Chrome Dev Tools beim Laden der Site nachsehen, sind React und React-dom (die minimierten Versionen) auf einer GZipped HTTP-Verbindung nur 47 KB Netzwerkverkehr, was weniger ist als die meisten Bilder auf einer Site, also bin ich es nicht Ich mache mir Sorgen, dass ich sowieso versuchen könnte, so viel zu reduzieren, es sei denn, es gibt wirklich große Gewinne (z. B. 50% Reduktion).

Als Nachtrag: Ich möchte auch darauf hinweisen, dass Sie ohne diese Option die Leute dazu zwingen, einen Bundler zu verwenden, der diese Importe eliminiert, da der TypeScript-Compiler selbst keine Konfiguration für die Angabe "Dieses Modul ist wirklich global" hat und dies auch tun wird Emporte für Module ausgeben (oder erfordern oder definieren), die zur Laufzeit nicht aufgelöst werden.

@billti SystemJS unterstützt dieses Szenario vollständig. Sie können zwischen der Verwendung eines lokal installierten Pakets während der Entwicklung und der Verwendung eines CDN in der Produktion wechseln. Es bietet auch volle Unterstützung für Metadaten, die angeben, dass alle Importe tatsächlich Verweise auf eine globale Variable anzeigen sollen, die einmal abgerufen und bei erstmaliger Verwendung an das Fensterobjekt angehängt wird. In der Produktion kann dies von einem CDN stammen. Ich habe dies nicht mit React gemacht, aber ich habe es mit Angular 1.x gemacht

Danke @aluanhaddad . Interessant ... Ich habe tatsächlich versucht, etwas Ähnliches zum Laufen zu bringen, das mich zu dieser Straßensperre führte, und konnte es nicht herausfinden. Deshalb habe ich erst heute Morgen die Frage zum SystemJS-Repo gestellt. Wenn Sie antworten können, wie Sie https://github.com/systemjs/systemjs/issues/1510 erreichen, wäre das wirklich hilfreich :-)

Hinweis: Mein anderer Kommentar lautet weiterhin, dass die Ausgabe von TypeScript selbst ohne diese Option nicht verwendet werden kann, da Sie beispielsweise SystemJS / WebPack / Rollup usw. benötigen, um die Importe Globals zuzuordnen, damit der Code ausgeführt werden kann.

Ich werde einen Blick darauf werfen und sehen, ob ich ein funktionierendes Beispiel machen kann. Ich habe es schon eine ganze Weile nicht mehr gemacht und ich habe keinen Zugriff auf den Quellcode, den ich damals hatte, aber ich bin hundertprozentig sicher es ist möglich.

Bis zu Ihrem zweiten Punkt ist es genau das, was SystemJS tut. Diese Importe werden dem globalen zugeordnet und es wird verstanden, dass das globale tatsächlich angefordert wird und bereits geladen wurde. Die Ausgabe ist definitiv verwendbar

Zu Ihrer Information: Ich habe dies in SystemJS mithilfe der SystemJS-API zum Laufen gebracht und meine Lösung unter https://github.com/systemjs/systemjs/issues/1510 hinzugefügt. Vielen Dank.

Zu meinem zweiten Punkt: Ja, ich weiß, dass die Lader genau das können. Das ist mein Punkt, sie können ein importiertes Modul einem globalen Modul zuordnen, TypeScript jedoch nicht. Sie müssen also einen Loader verwenden, um Ihren Code zur Laufzeit gültig zu machen. Es handelt sich also um einen Catch-22 mit dieser ursprünglichen Ausgabe, bei der Sie nicht deklarieren können, dass das globale (in diesem Fall React) im Modul verfügbar ist. Sie müssen es importieren, als wäre es ein Modul (was es nicht ist). .

Mein anderer Kommentar ist immer noch, dass die Ausgabe von TypeScript selbst ohne diese nicht verwendbar ist, da Sie etwas wie SystemJS / WebPack / Rollup usw. benötigen, um die Importe Globals zuzuordnen, damit der Code ausgeführt werden kann.

@ Billti Ich verstehe nicht. Was ist ein Szenario, in dem Sie nur die globale Version eines Moduls verwenden können, TypeScript dies jedoch nicht zulässt? Ich habe nur Szenarien gesehen, in denen eine Bibliothek sowohl als globales als auch als Modul verfügbar ist.

@DanielRosenwasser Ich denke, er meint, dass React zur Laufzeit tatsächlich global ist, wie in einem Mitglied des globalen Objekts, weil es geladen wird.

@ Billti Super, dass du es zum

Zu Ihrem zweiten Punkt: Ich verstehe, was Sie meinen.

Ich nehme an, ich habe das Gefühl, dass Sie in einem Browserszenario entweder einen Loader wie RequireJS oder einen Packager wie Webpack verwenden müssen, da kein Browser Module unterstützt, dies jedoch keinen Unterschied macht. (Ich höre, Chakra hat es hinter einer Flagge zur Verfügung). Es gibt also keine Möglichkeit, den Code ohne ein zusätzliches Tool auszuführen. Es ist eine Art Implikation der Ausgabe, die define , require oder System.register dass der ausgegebene JavaScript-Code wahrscheinlich nicht portierbar ist. Ich sehe jedoch die Bedeutung der Unterscheidung "Modul gegen kein Modul".

Mit dieser Problemumgehung können Sie mindestens einmal auf das "Modul" verweisen.

_shims.d.ts_

import __React from 'react';

declare global {
  const React: typeof __React;
}

Dann können Sie es überall verwenden, ohne es zu importieren.
Auch dies ist sehr explizit, wenn auch etwas klobig, weil Sie sagen, dass React global geworden ist und dies auch der Grund ist, warum Sie es nicht mehr importieren müssen.

Re your shims.d.ts, wenn du ein paar Posts hoch gehst, wirst du sehen, dass ich das jetzt getan habe (große Köpfe denken gleich) ;-)

Ich kann es jetzt auf verschiedene Arten zum Laufen bringen, das ist nicht der Punkt. Wir versuchen, TypeScript einfach zu übernehmen und Benutzer in die Grube des Erfolgs zu geraten, nicht in die Grube der Verzweiflung. In diesem Sinne stelle ich mir oft zwei Fragen, wenn ich versuche, TypeScript zu verwenden und Probleme zu lösen: a) Ist dieser Code gültig und b) Werden Kunden versuchen, dies zu tun?

Da die (Nicht-TypeScript-) Version in Babel ungefähr in der Zeit, in der ich sie eingegeben habe, das getan hat, was ich wollte, ist es fair zu sagen, dass der Code gültig ist. Da die Installationsseite der React-Dokumente zeigt, wie Skript-Tags von einem CDN verwendet werden , um React einzuschließen, werden dies vermutlich auch einige Leute versuchen. (FWIW: Ich habe mehr Zeit damit verbracht, mich daran zu erinnern, mit verschiedenen JS-Modulen und -Ladern gearbeitet zu haben. Es ist also nicht so, als ob ich sie nicht kenne. Ich wollte meinen Code nur so schreiben.)

Wenn TypeScript bestimmte gültige Muster für das Schreiben von Code nicht unterstützt, sollten wir versuchen, dies sofort offensichtlich zu machen und die Leute richtig zu steuern (was bei Fehlermeldungen oder prägnanten Dokumenten eine Herausforderung darstellt). Ich persönlich denke jedoch nicht, dass TypeScript keine Muster unterstützen sollte, da wir nicht der Meinung sind, dass es sich um "Best Practices" oder "Canonical" handelt. Wenn der Code gültig ist und einige JavaScript-Entwickler ihn möglicherweise schreiben möchten, sollte TypeScript versuchen, ihn zu unterstützen. Je mehr wir verlangen, dass sie ihren Code ändern und ihre Build-Pipeline neu konfigurieren, damit TypeScript funktioniert (wie hier empfohlen, um meine triviale App zu migrieren), desto weniger Entwickler werden umsteigen.

Was die Lösung angeht ... hier nur spucken, aber vielleicht könnte die Compileroption "lib", die bereits effektiv definiert, welche APIs im gesamten Projekt verfügbar sind, auch Formatwerte im Format @types/name für Bibliotheken verwenden, um sie global hinzuzufügen (und vielleicht sogar relative Pfade unterstützen).

Wir versuchen, TypeScript einfach zu übernehmen und Benutzer in die Grube des Erfolgs zu geraten, nicht in die Grube der Verzweiflung.

Ich denke , dass wir die Nutzer versuchen , jetzt in die Grube von Erfolg zu führen. Wenn ein Modul eine globale Bedingung nur bedingt definiert, führen Sie Benutzer versehentlich dazu, etwas zu verwenden, das nicht vorhanden ist. Ich sehe also einige verschiedene Optionen:

  1. Erstellen Sie ein erweitertes export as namespace foo -Konstrukt, das nur sichtbar ist, wenn es nicht von einem Modul importiert wird.
  2. Tun Sie nichts und drängen Sie die Leute weiter, den Import zu verwenden - dies ist meiner Meinung nach mehr oder weniger in Ordnung, da wir die Fehlermeldung ohnehin einigermaßen vorgeschrieben haben.
  3. Erlauben Sie den Leuten, die UMD von überall aus zu nutzen - ich bin ehrlich gesagt nicht so begeistert von dieser Idee.

@ Billti

Re your shims.d.ts, wenn du ein paar Posts hoch gehst, wirst du sehen, dass ich das jetzt getan habe (große Köpfe denken gleich) ;-)

Sorry, das habe ich verpasst, sehr nett;)

Ich denke nicht, dass TypeScript keine Muster unterstützen sollte, da wir nicht glauben, dass sie "Best Practices" oder "kanonisch" sind.

Ich denke nicht, dass TypeScript hier proskriptiv ist, ich denke, es tut, was es behauptet, und sagt mir, dass ich einen Fehler habe. Viele Bibliotheken haben Demos und Tutorials, in denen sie sich selbst als Globals laden und dann die ES-Modulsyntax verwenden. Ich denke nicht, dass sie damit die größten Bürger sind, aber das ist eine andere Diskussion.

Das heißt, wenn Module hauptsächlich als wahrgenommener syntaktischer Zucker über Globals verwendet werden, liegt ihr Fehler nahe, weil sie überhaupt kein syntaktischer Zucker sind. Wenn überhaupt, handelt es sich um ein syntaktisches Salz (möglicherweise eine Steuer?), Das wir für Vorteile wie echte Codeisolation, Freiheit von Skript-Tag-Ording, explizite Abhängigkeitsdeklaration, Flucht aus der Hölle des globalen Namespace und andere Vorteile verbrauchen. Die Syntax für Module ist nicht ergonomisch, sie ist bestenfalls ausführlich, aber es ist die Semantik der Module, die es lohnenswert macht.

Ich denke, wenn Leute TypeScript verwenden, zumindest in .ts -Dateien, gehe ich davon aus, dass sie die Vorteile einer starken statischen Code-Analyse nutzen möchten. Babel tut dies nicht, vorausgesetzt, React existiert, hat aber keine Kenntnis davon. Dies gilt auch dann, wenn ES-Module absichtlich so spezifiziert wurden, dass sie für statische Analysen geeignet sind.

@ DanielRosenwasser

Erstellen Sie einen erweiterten Export als Namespace-Foo-Konstrukt, der nur sichtbar ist, wenn er nicht von einem Modul importiert wird.

Das klingt nach dem besten Weg, dies zu lösen.

Hier ist ein weiterer Fall, in dem dies Probleme verursachte:

In einem Projekt, an dem ich gerade arbeite, mischen wir lokale Includes (hauptsächlich aus historischen Gründen) mit npm-Modulen. Am Ende wird alles mit Rollup oder Browserify verbunden, das ist also in Ordnung.

Ich verwende eine .js-Datei aus dem Emojione-Projekt, die ich einfach in die Codebasis kopiert habe. Später habe ich die Typdeklarationen dafür zu DefinitelyTyped hinzugefügt: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/13293 Ich dachte, ich könnte jetzt einfach die Typen laden und alles würde funktionieren. Dies scheint jedoch nicht der Fall zu sein, da ich mit TypeScript nicht auf die globale Version zugreifen kann.

Der Grund, warum ich nicht zum npm-Modul wechsle, ist, dass das npm-Modul auch mehrere Megabyte Sprites und PNGs bündelt. Ich brauche nur dieses eine 200KiB-Skript. Mit Typdeklarationen.

Bei AngularJS declare var angular: ng.IAngularStatic die Problemumgehung

@dbrgn Sie haben ein anderes Problem. Wenn das Modul tatsächlich ein globales Modul ist, ist Ihre Typdefinition falsch. Es deklariert weder eine globale noch eine UMD-Stildeklaration (hier geht es um UMD-Stildeklarationen), sondern deklariert tatsächlich nur ein reines ES-Modul.

Wenn das Modul ein globales Modul darstellt, exportieren Sie es nicht auf der obersten Ebene der Datei. Dies macht es zu einem Modul.

Mit AngularJS wurde die Problemumgehung als var angular deklariert: ng.IAngularStatic. Aber das funktioniert nicht mit Namespaces, oder?

Es funktioniert mit Namespaces.

Das Ergebnis der Diskussion bei unserem Designtreffen war, dass wir erwägen, die UMD immer zuzulassen und ein Flag hinzuzufügen, das die aktuelle Einschränkung erzwingt. Die Einschränkung wird auch erweitert, um auf den Zugriff auf Typen von einem UMD-Global aus zu arbeiten.

Nachdem ich mehr darüber nachgedacht habe, denke ich immer noch, dass es besser ist, eine neue Deklarationsart zu erstellen. Dieses Flag ist weniger erkennbar als die neue Syntax, die vom Autor der Deklarationsdatei nur einmal geschrieben werden muss.

Dies wird für vorhandenen Code und Tools dringend benötigt. Bis Javascript nicht mehr schnell spielt und mit Modulsystemen verliert, benötigen wir Flexibilität, um mit dem vorhandenen Code arbeiten zu können. Geben Sie eine Warnung aus, aber schlagen Sie den Build nicht fehl. Ich habe Tage damit verschwendet, Legacy-Code mit Rollup und Typoskript gut spielen zu lassen.

PFUI.

Ich weiß, dass es viele Leute gibt, die gerne über Java lachen, aber grundlegende Java-Module funktionieren zumindest. Gläser arbeiten

Ich muss nicht 14 verschiedene Ad-hoc-Modulstandards anpassen oder versuchen, ein js-Modul aus Quelldateien in dem Format zu kompilieren, das das Rollup- / Bundling-Tool des Tages tatsächlich verbraucht, ohne sich selbst zu kacken, und auch ein Modulformat generieren Das passt gut zu Typescript-Import / Export-Anweisungen und d.ts-Dateien von Drittanbietern, sodass TSC tatsächlich beschließt, den Code zu erstellen, anstatt über etwas zu jammern, wohin Sie gehen LAUFZEIT ".

Der shims.d.ts Hack funktioniert gut. Aber ugh.

Temporäre Lösung für Benutzer von Webpack https://github.com/Microsoft/TypeScript/issues/11108#issuecomment -285356313

Fügen Sie externals zu webpack.config.js mit den gewünschten UMD-Globals hinzu.

    externals: {
        'angular': 'angular',
        'jquery': 'jquery'
        "react": "React",
        "react-dom": "ReactDOM"
    }

Ich denke, dies sollte möglich sein, um die Migration vorhandener Codebasen zu vereinfachen.

Ich habe ein Projekt mit requirejs implementiert, in dem jQuery als global enthalten ist, da es einige Plugins gibt, die jQuery nur erweitern, wenn es als global gefunden wird.

Der Code in einigen Modulen hängt von diesen Plugins ab, die nicht verfügbar wären, wenn jQuery als Modul importiert würde. Damit dies funktioniert, müsste ich alle Plugins so ändern, dass sie mit jQuery funktionieren, das als Modul geladen ist, und sie auch als Module laden (eine Vermutung, wo sie notwendig sind).

Außerdem gibt es auch Seiten, die Javascript ohne Modullader verwenden. Die Plugins sollten also sowohl mit Globals als auch mit Modulen funktionieren.

Abgesehen von jQuery gibt es andere Skripte mit dem gleichen Problem wie Knockout und andere. Dies macht die Migration des Projekts zu einem Trottel. Oder aus realistischer Sicht nicht realisierbar.

Natürlich ist dies nicht das beste Muster, und ich würde es nicht in einem neuen Projekt verwenden. Aber ich glaube nicht, dass ich der einzige mit diesem Problem bin

Wäre es sinnvoll, dafür types in tsconfig.json zu verwenden? ZB ohne types set erhalten Sie das aktuelle implizite Verhalten und mit types set sagen Sie buchstäblich "diese Dinge sind global" und können den UMD-Namespace dazu zwingen, global zu erscheinen. Das ist das Verhalten, das heute sowieso existiert (abzüglich der globalen Kraft). Dies steht im Gegensatz zur Einführung einer neuen Option globals .

Ich denke das ist eine gute Idee. In meinem Fall gibt es Skripte, die eine UMD-Bibliothek als global und andere als Modul verwenden. Ich könnte dieses Problem mit zwei verschiedenen tsconfig.json lösen, die jeweils angesprochen werden. Wirklich geradlinig.

@blakeembrey Obwohl die Verwendung von types sinnvoll ist, bin ich nicht besonders daran interessiert, es zu überladen, da es bereits Probleme gibt. Beispielsweise hat das Konstrukt <reference types="package" /> bereits die Einschränkung, dass es "paths" nicht unterstützt. Die "package" müssen sich auf einen Ordnernamen in @types beziehen

Es fällt mir schwer, diesem Gespräch zu folgen. Gab es dafür Updates oder geplante Lösungen? Es scheint, dass dies in Szenarien nützlich sein könnte, z. B. wenn lodash ein wesentlicher Bestandteil einer Anwendung ist oder wenn mehr Bibliotheken von Drittanbietern in eine modularisierte Struktur konvertiert werden, anstatt sich nur auf das Fenster zu verlassen.

Gibt es eine geplante Möglichkeit, dies zu beheben oder zumindest zu dokumentieren, wie dies mit der aktuell verfügbaren Version gelöst werden soll?

Hallo @mochawich, ich wenn ich React als extern definiere und nicht die Syntax declare global :

TS2686: 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.

@cantux TypeScript liest die Webpack-Konfiguration nicht. Wenn Sie React global verfügbar gemacht haben, können Sie das declare , aber warum nicht Module verwenden?

@aluanhaddad vor allem, weil ich mit der Arbeit durch Importaufruf verwirrt war. Ich habe einiges herumgespielt, sind die folgenden Aussagen richtig?

Wir zahlen die geringe Gebühr für eine Anfrage, wenn wir ein Modul importieren. Dadurch wird sichergestellt, dass das, was wir verwenden, im Speicher verfügbar ist. Wenn es zuvor angefordert wurde, wird das Modul aus dem Cache geladen. Wenn das Modul nicht vorhanden ist, wird es abgerufen. Wenn Sie diese Anforderung umgehen möchten, definieren Sie etwas einfach als global und Typescript vertraut Ihnen blindlings, dass es verfügbar ist (und wenn Sie einen Smart Bundler verwenden, können Importanweisungen sogar ersetzt / entfernt werden).

Wenn diese korrekt sind, können wir die Kommentare der Kürze halber entfernen. Der Thread ist so wie er ist ein Riese.

Kann jemand, wie

Meine derzeitige Problemumgehung bestand darin, die typedef-Datei so zu hacken, dass sie dem alten Arbeitsstandard entspricht. Dies ist jedoch nicht möglich, wenn mehr typedef-Dateien beschädigt werden.

Mein Szenario ist wie folgt:

  • In meinen einseitigen Apps importiere ich eine Reihe von Bibliotheken (einschließlich lodash) in a

Das oben erwähnte Shim-Beispiel funktioniert, obwohl vscode es als Fehler hervorhebt (obwohl es die Fertigstellung immer noch richtig macht!).

Bitte, bitte, bitte geben Sie keine Fehler beim Zugriff auf UMD-Globals in Modulen. Das massive Projekt, an dem ich arbeite, wird in AngularJS durchgeführt und wir verwenden Typescript für die Anwendung, aber natürlich benötigen wir Typescript, um die globalen und Angular-Typen angular UMD von @types/angular . Sie würden denken, es wäre so einfach, wie "angular" zu types in tsconfig.json hinzuzufügen, aber aus irgendeinem Grund ist es nicht so, und TSC schreit mich an. So sehr ich mir wünschte, alle NPM-Pakete wären reines Typescript, die meisten von ihnen sind einfache JS und werden es für eine sehr lange Zeit sein. Ich verstehe wirklich nicht, warum TSC nicht einfach die Klappe halten kann, wenn wir ein d.ts importieren, das besagt, dass ein UMD-Global vorhanden ist. Diese Situation ist mehr als häufig - jedes Typescript-Projekt, an dem ich jemals gearbeitet habe, verwendet mindestens eine JS-Bibliothek, die ich selbst bündeln und mithilfe von Typdefinitionen referenzieren muss.

Gibt es ein Update dazu?

Mein Anwendungsfall: Ich arbeite an einer großen vorhandenen Codebasis, die CDNs stark nutzt. Allgemeine Dienstprogramme werden über Skript-Tags auf vielen Seiten importiert (z. B. Zwischenablage, lodash). Ich möchte auf diese globalen Variablen verweisen, da sie auf der Seite verfügbar sind. Ohne die Verwendung von Modulen ist es einfach genug, Typoskript kompilieren zu lassen, wobei /// <reference type="$name" /> oben in den relevanten Quelldateien verwendet wird. Dies funktioniert jedoch nicht mehr, wenn Sie versuchen, Module zu erstellen.

Es scheint, dass im Thread zwei Ansätze vorgeschlagen wurden:

  1. Lassen Sie die /// <reference type="$name" /> Token nur in den Namespace der aktuellen Datei importieren.

  2. Eine Compileroption / Konfigurationsvariable in tsconfig.json (z. B. "globals" , "types" )

Ich finde beide Ansätze gut. Während ich der Kritik an Option 1 von @RyanCavanaugh zustimme :

Umgekehrt, wenn es nur in dieser Datei verfügbar ist, müssen Sie überall Referenzanweisungen kopieren und einfügen, was wirklich ärgerlich ist.

Ich finde es viel ärgerlicher, dass Sie aufgrund des aktuellen Verhaltens überhaupt keine Module zusammen mit UMD-Globals verwenden können. Einige Problemumgehungen sind besser als keine.

Ist dieses Problem noch offen? Und wenn ja, wie lautet die aktuelle Problemumgehung?

Wenn Sie das Paket @types installieren, werden die Pakete, die nicht als Module importiert wurden, als globale Pakete verfügbar gemacht.

Wenn ich beispielsweise npm install -D @types/underscore im Stammverzeichnis meines Projekts habe, kann ich Module schreiben, die nichts aus dem Unterstrich importieren, aber das globale _ wird verfügbar gemacht (siehe unten).

types-ref

Ist es das, wonach du suchst?

@billti Vielleicht

Minimal notwendig zum Repro:

js / foo.ts:

// <reference types="js-cookie">

import { Bar } from "./bar";

const Foo = {
    set: function() {
        Cookies.set("foo", "bar");
    },
    get: function() {
        console.log(Cookies.get("foo"));
    }
};

window.onload = function() {
    console.log(Cookies);
}

js / bar.ts.

const Bar = {
    x: 3
};

export { Bar };

package.json:

{
  "name": "foo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "devDependencies": {
    "@types/js-cookie": "^2.1.0",
    "typescript": "^2.7.1"
  },
  "dependencies": {
    "http-server": "^0.11.1"
  }
}

tsconfig.json

{
    "compilerOptions": {
        "module": "system"
    },
    "files": [
        "js/foo.ts"
    ]
}

Fehlermeldungen:

js / foo.ts (7,3): Fehler TS2686: 'Cookies' bezieht sich auf eine UMD global, aber die aktuelle Datei ist ein Modul. Fügen Sie stattdessen einen Import hinzu.
js / foo.ts (10,15): Fehler TS2686: 'Cookies' bezieht sich auf eine globale UMD, aber die aktuelle Datei ist ein Modul. Fügen Sie stattdessen einen Import hinzu.
js / foo.ts (15,14): Fehler TS2686: 'Cookies' bezieht sich auf eine globale UMD, aber die aktuelle Datei ist ein Modul. Fügen Sie stattdessen einen Import hinzu.

Das Verhalten, das Sie erhalten, hängt davon ab, ob das importierte Modul als "richtiges" UMD-Modul (dies ist das Verhalten bei "Cookies") oder als "funktioniert in beide Richtungen gleichzeitig" -Modul geschrieben wurde (so wird lodash geschrieben). .

Die Inkonsistenz der Leute, die eine .d.ts-Datei korrekt schreiben, die beschreibt, wie das Objekt zur Laufzeit funktioniert, und die Undurchsichtigkeit der Erfahrung für Entwickler, ist der Grund, warum ich mich ziemlich stark in die Richtung "UMD Global Restriction entfernen" neige. Wir könnten es mit einem Opt-out von --noStrictUMD unter --strict .

Das andere, was mir begegnete, war der Umgang mit Monacos speziellem AMD-Lader. Sie unterstützen eine Teilmenge des AMD-Verhaltens (fügen Sie ein riesiges Eyeroll ein), stampfen jedoch auf das globale "Erfordernis", sodass es wirklich schwierig ist, geeignete UMD-Module damit zu verwenden, da diese Module dazu neigen, das "Erfordernis" global zu sehen und dann nicht richtig in das zu laden Monaco Modullader. Am Ende platzieren Sie die UMD JS-Bibliotheken über dem Skript-Tag für den Monaco-Loader, und dann beschwert sich TS, weil Sie von einem Modul aus auf die Globals zugreifen (was Sie sein müssen, um die Monaco-APIs zu importieren).

@ RyanCavanaugh

Das andere, was mir begegnete, war der Umgang mit Monacos speziellem AMD-Lader. Sie unterstützen eine Teilmenge des AMD-Verhaltens (fügen Sie ein riesiges Eyeroll ein), stampfen jedoch auf das globale "Erfordernis", sodass es wirklich schwierig ist, geeignete UMD-Module damit zu verwenden, da diese Module dazu neigen, das "Erfordernis" global zu sehen und dann nicht richtig in das zu laden Monaco Modullader.

😁

Gibt es eine Chance, dass sie das beheben?

Ich habe in letzter Zeit viel über die Komplexitätskosten von Modulen nachgedacht. So viele voneinander abhängige, teilweise kompatible Loader, Bundler, Transpiler, Paketmanager und Frameworks machen eine wirklich nicht triviale Komplexität der Akkreditierung aus. (Ich bin sicher, Sie brauchen überhaupt keine Erinnerung 🙉).

Als Entwickler haben wir Toolchains akzeptiert, die um Größenordnungen komplexer sind als vor 5 bis 6 Jahren, und die Hauptursache für Komplexität waren Module.

Wofür war das alles, wenn wir aufgeben und anfangen, diese UMD-Pakete als globale Dateien zu laden?

Und doch ... machen die Leute genau das. Das ist fürchterlich!

Ich meine, diese Stapelüberlauf- Antwort hat 61 👍s und hat im letzten halben Jahr für 99% der Pakete die falschen Dinge vorgeschlagen. (Der Autor hat es freundlicherweise aktualisiert, um Module als Option für UMD-Abhängigkeiten zu erwähnen, da heute Morgen einige Rückmeldungen gegeben wurden.)

Dies kann nicht zulassen, dass all dies in die Quere gekommen ist und zu den Globalen zurückkehrt!

Und doch ... machen die Leute genau das. Das ist fürchterlich!

Das Problem ist, dass JS-Module furchtbar schlecht konzipiert und implementiert sind, so dass es viel besser und einfacher ist, wieder Globals zu verwenden. Wenn Module von Anfang an richtig entworfen und implementiert wurden ...

Wir kombinieren Module und UMD-Globals, weil es viel zu mühsam ist, unsere Abhängigkeiten als Module mit unterschiedlicher Kompatibilität mit verschiedenen Loadern zu laden, und einige Loader unterstützen keine direkte Abhängigkeitsbündelung. Stattdessen müssen Sie unseren speziellen Präprozessor verwenden, der a benötigt Minute zu laufen.

Diese "Funktion" bedeutet nur, dass wir die offizielle UMD-Modulunterstützung nicht verwenden, obwohl wir tatsächlich UMD-Module verwenden. Wir exportieren einfach als Global aus der .d.ts-Datei und haben dann manuell ein eigenes Modul mit diesem Namen, das alles erneut exportiert.

Gibt es hierzu Neuigkeiten? Ich möchte wirklich, dass Option 2 funktioniert:

Lassen Sie eine Syntax oder Konfiguration zu, dass "diese UMD global tatsächlich global verfügbar ist".

Es hilft auch nicht, dass es so viele js libs im Old-School-Stil gibt
dort, und sie alle neu zu schreiben, kommt nicht in Frage. Ich arbeite gerade einen soliden aus
config, damit Rollup sie alle richtig handhabt, verschwendet Stunden meiner Zeit.

Die Leute lachen über "Enterprise Java", aber einfaches Java wird mit einem funktionsfähigen ausgeliefert
Modulsystem bei 1.0. War nicht perfekt, aber kein komplettes Durcheinander.

Da es sich um "Globale im UMD-Stil zulassen" handelt, sollte dies auf jeden Fall eine Option sein.

Am Montag, 2. April 2018, um 01:40 Uhr Kagami Sascha Rosylight <
[email protected]> schrieb:

Ich musste umgehen mit:

/ * Modul: es2015 * /
// js-yaml unterstützt UMD, aber nicht das ES2015-Modul! import * as _jsyaml from "js-yaml"; deklariere var jsyaml: typeof _jsyaml; jsyaml.safeLoad ("");

- -
Sie erhalten dies, weil Sie kommentiert haben.
Antworte direkt auf diese E-Mail und sieh sie dir auf GitHub an
https://github.com/Microsoft/TypeScript/issues/10178#issuecomment-377885832 ,
oder schalten Sie den Thread stumm
https://github.com/notifications/unsubscribe-auth/AA50ljAD33sr09EGFVAsURbu1x75X-lOks5tkeQCgaJpZM4Jd8jX
.

>

Daniel Joyce

Die Sanftmütigen werden die Erde erben, denn die Tapferen werden unter den Sternen sein.

Ich verwende three.js in einem Angular-Projekt. Ich importiere es als

import * as THREE from "three";

import {Vector3} from "three"; funktioniert auch wie erwartet.

Mit den installierten Paketen three und @types/three npm funktioniert alles einwandfrei. Unter der Haube, denke ich, verwendet dies three/build/three.module.js . Die @types/three/index.d.ts -Datei verwendet die Notation export as namespace THREE , mit der ich nicht ganz vertraut bin, aber hey, es funktioniert.

In diesem speziellen Fall besteht das Problem darin, dass es im three.js-System eine andere verwandte Datei gibt, die OrbitControls.js (mit der Sie 3D-Bilder grundsätzlich mit Ihrem Finger oder Ihrer Maus drehen können). Das Problem ist, dass diese Funktion, obwohl sie halbamtlich Teil der three.js-Distribution ist, eine einfache alte JS-Datei ist, die im examples -Baum gefunden wird und sich direkt in der THREE -Eigenschaft befindet des Fensters und verwendet direkt andere APIs, von denen erwartet wird, dass sie auf window.THREE . Also auch wenn ich die Datei mit "benötige"

require("three/examples/js/controls/OrbitControls.js");

Es kann nicht window.THREE , um sich selbst anzulegen oder auf andere Teile des von ihm verwendeten DREI-Systems zuzugreifen. Ich kann die gesamte Bibliothek direkt mit der Angular scripts -Eigenschaft in angular.json einbinden (entspricht ungefähr einem altmodischen <script> -Tag), aber wenn ich mich nicht irre wird die Bibliothek zweimal geladen haben.

Um dies zu vermeiden, habe ich die import * as THREE from "three"; -Anweisung entfernt, und hey, sie kann immer noch Typen wie foo: THREE.Vector3 auflösen, verschluckt sich jedoch an Referenzen wie new THREE.Vector3() mit dem berüchtigten

'DREI' bezieht sich auf eine globale UMD, aber die aktuelle Datei ist ein Modul. Fügen Sie stattdessen einen Import hinzu. [2686]

An diesem Punkt denke ich, dass ich nur die OrbitControls.js -Datei und ES6-ify und / oder TS-ify greifen muss, was anscheinend mehr als eine andere Person bereits getan hat die Form von Dingen wie `orbit-control-es6 , also sollte ich vielleicht einfach mein Leben vereinfachen und das nutzen, obwohl ich es hasse, mein Leben auf diese Weise in die Hände anderer Leute zu legen.

Eine Kuriosität ist, dass @types/three Typen für OrbitControls , selbst wenn sich der Code selbst nicht im Modul three . Ich kann jedoch nicht herausfinden, wie all diese Typen, die eine Klasse mit dem Namen OrbitControls mit irgendetwas verknüpft werden können. Ich möchte den Standardexport der oben genannten orbit-controls-es6 deklarieren dieser Typ, aber wie das geht, entgeht mir.

Die Lösung, für die ich mich schließlich schäme, ist:

import * as THREE from "three";
Object.defineProperty(window, "THREE", {get() { return THREE; }});
require("three/examples/js/controls/OrbitControls.js");

Es funktioniert, obwohl ich etwas verwirrt bin, warum. Die erforderliche Datei hat eine Zeile wie

THREE.OrbitControls = funtion() { };

was so aussieht, als würde es dem DREI "Namespace" zugewiesen, der sich aus der Anweisung import * as THREE from "three"; ergibt, was nicht funktionieren sollte, oder?

@ RyanCavanaugh hat mich gebeten, mein Feedback von # 26223 hier zu kopieren:

Ich pflege eine ziemlich große TypeScript-Codebasis (Googles interne Monorepo), die mehrere definitiv typisierte Bibliotheken enthält, von denen die Leute abhängig sind. Ursprünglich verwendeten Benutzer nur globale Typen für Bibliotheken wie angular , bevor die .d.ts in externe Module umgewandelt wurden. Anschließend haben wir die Codebasis migriert, um Module und explizite Importe zu verwenden. Wir haben tatsächlich erwartet, dass export as namespace d UMD-Globals immer einen expliziten Import erfordern würden, um Symbole sowohl für Typ- als auch für Wertreferenzen zu verwenden, und haben bei der Migration nicht einmal bemerkt (whoops).

Das Zulassen der nicht importierten Verwendung von Code ist für uns im Allgemeinen problematisch:

  • Dies bedeutet, dass Code auf globalen Definitionen des Typs "Hintergrund" basiert, wodurch das Lesen von Code schwieriger wird (insbesondere in Repo-Browsern oder bei der Codeüberprüfung ohne Symbol).

  • Es verdeckt Code-Abhängigkeiten

  • Es umgeht die Einschränkungen, die wir in bazel implementieren, auch bekannt als "strenge Deps", "muss eine explizite Abhängigkeit auf Build-Ebene von allen Importen haben".

    In einer großen Codebasis muss Ihr Code explizite Abhängigkeiten aufweisen, da sonst das Repo nicht mehr verwaltet werden kann. Wenn Sie nun eine Abhängigkeit haben, die A -> B -> C und globale Typen verändert, ist es einfach, Code A kompilieren zu lassen, nur weil B eine Abhängigkeit von C . Wenn B später seine Abhängigkeit aufhebt, wird A , was bedeutet, dass Änderungen unerwartete Auswirkungen auf das Repository haben und die Codeisolation verletzen.

  • Es bewirkt, dass Code das Modul mit einem Präfix für Werte inkonsistent importiert und seine Typen mit einem anderen Präfix verwendet (insbesondere für AngularJS, ng vs angle).

Wir können dies umgehen, indem wir diese export as namespace -Anweisungen in unserer vom Hersteller bereitgestellten Kopie von DefinitelyTyped entfernen. Zumindest für uns wirkt diese Funktion der Wartbarkeit des Codes und unseren technischen Zielen entgegen. Ich denke, die Probleme sind in einer Monorepo-Situation wie Google stärker ausgeprägt, gelten aber im Allgemeinen auch für kleinere Codebasen.

Die Punkte, die Sie veröffentlicht haben, sind für unsere Situation absolut unerheblich. Wir sind gezwungen, unseren eigenen Code mit AMD-Modulen zu implementieren und unsere Abhängigkeiten mit UMD-Modulen zu versorgen, da Umstände weit außerhalb unserer Kontrolle liegen (aber ich würde zusammenfassen, dass JS-Module sowohl im Konzept als auch in der Implementierung schrecklich fehlerhaft sind). Diese Funktion würde es uns ermöglichen, unser Leben erheblich zu vereinfachen.

Möglicherweise könnten wir mit TS3 herausfinden, wie wir dies vermeiden können, aber selbst wenn wir dies tun würden, würde es wahrscheinlich mindestens zwei Jahre dauern, bis wir alle erforderlichen Änderungen abgeschlossen haben. Dies wäre also immer noch eine sehr nützliche Funktion für uns.

Offene Frage: Wäre ein globales Flag für "Zugriff auf alle UMD-Module zulassen" ausreichend, oder benötigen die Benutzer wirklich die Kontrolle über den Fehler pro Modul?

Stimmen Sie ❤️ für "nur eine Flagge"
Stimmen Sie 🎉 für "Pro-Modul-Steuerung benötigen" ab

Ich habe auch darüber nachgedacht, ob das Vorhandensein einer expliziten Liste in der Option "types" in tsconfig.json nicht auch die UMD-Verwendung in einem Modul

In ähnlicher Weise sollte die Verwendung eines /// <reference types="..." /> -Konstrukts die UMD-Verwendung dieses Pakets in dem Modul ermöglichen, in dem es verwendet wird (dh die erwähnte Steuerung "pro Modul").

@ RyanCavanaugh Wird es auch eine Flagge für die Adresse # 26233 geben?

26233 gilt als voll funktionsfähig wie beabsichtigt; Der Zugriff auf die Typenseite eines UMD Global von einem Modul aus ist zu Recht harmlos

Ich bin mir nicht ganz sicher, ob es "rechtmäßig harmlos" ist. Am Beispiel von @types/jquery . $ und jQuery werden der Schnittstelle JQueryStatic und als Konstanten exportiert. Infolgedessen können alle Module ohne Import auf $ und jQuery zugreifen. Ich hoffe ich kann das deaktivieren.

@ RyanCavanaugh ja, es ist harmlos in dem Sinne, dass die TS-Emission nicht davon betroffen wird. Es ist problematisch, wenn Sie genau steuern möchten, auf welche @types jede Bibliothek zugreifen kann - es verwandelt zumindest Typen mit Modulbereich in globale Typen. Die Erweiterung des Zugriffs kann ebenfalls ein Problem sein, selbst wenn die Ausgabe nicht betroffen ist.

Im jQuery-Fall ist die Ausgabe tatsächlich betroffen. $() wird in einem Modul ohne Import ausgegeben.

Akzeptieren von PRs für ein neues Flag, das den Zugriff auf UMD-Globals von allen Modulen aus ermöglicht.

In Bezug auf die Implementierung ist es recht einfach ... aber wir müssen es benennen. Wir haben ungefähr ein Dutzend schrecklicher Namen bei der Besprechung der Vorschlagsüberprüfung gekickt und sie alle gehasst, also liegt es an Ihnen, sich etwas Schmackhaftes auszudenken. Bitte halp.

Wir haben beim Vorschlagstreffen rund ein Dutzend schrecklicher Namen gekickt und sie alle gehasst

Was waren Sie?

Es liegt also an Ihnen, sich etwas Schmackhaftes auszudenken.

Vielleicht umdUseGlobal oder so.

Ich würde importAllNamespaces für den Namen des globalen UMD-Flags vorschlagen, da UMD-Globals normalerweise export as namespace .

@ RyanCavanaugh Hat das Team über das

@FranklinWhale ja.

@saschanaz Habe das schon gefragt, aber ich bin auch neugierig ... @RyanCavanaugh Erinnerst du dich, welche schrecklichen Namen besprochen wurden?

Ich denke, die Kette ist ungefähr so ​​gelaufen

  • allowUmdGlobalAccessFromModules - am genauesten, aber soooooo lang
  • assumeGlobalUmd - ugh
  • allowModuleUmdGlobals - "Globals" ??
  • umdAlwaysGlobal - 🤢
  • allowUmdGlobals - aber ich kann schon?
  • allowUmdGlobalAccess - überspringt den Modulteil, aber wahrscheinlich interessiert es niemanden?

Ich würde den letzten wählen, wenn ich dazu gezwungen würde

Vielen Dank!

Ich mag allowUmdGlobalAccessFromModules am besten, weil es, obwohl es lang ist, aufgrund seiner Präzision am einfachsten zu merken ist. Ich würde denken: "Was ist diese Option, mit der UMD-Globals von Modulen aus aufgerufen werden können? Oh ja, es ist natürlich allowUmdGlobalAccessFromModules !"

Die Verwendung des Präfixes "Zulassen" entspricht der Namenskonvention anderer Optionen, was gut ist.

Plus ... es gibt andere Optionen, die ungefähr so ​​lang sind :)

allowUmdGlobalAccessFromModules : 31 Zeichen

allowSyntheticDefaultImports : 28 Zeichen
strictPropertyInitialization : 28 Zeichen
suppressExcessPropertyErrors : 28 Zeichen
suppressImplicitAnyIndexErrors : 30 Zeichen
forceConsistentCasingInFileNames : 32 Zeichen

Was ist die aktuelle Problemumgehung? Ich habe in der letzten Stunde gegoogelt und kann keine praktikablen Lösungen finden.
Ich möchte lieber nicht auf 'any' umwandeln oder auf eine funktionierende Typescript-Version herunterstufen, kann aber keine anderen Optionen finden.
Gibt es irgendwo einen experimentellen Build mit einem Compiler-Flag, das dieses Problem behebt?
('allowUmdGlobalAccessFromModules' ist übrigens ein ausgezeichneter Name; es ist nicht so, als würden wir ihn 50 Mal am Tag tippen :-))

Wir verwenden tsc 3.2.2 mit lodash, das statisch in der obersten HTML-Datei enthalten ist. mit require.js; d.ts erhalten von neuesten DefinitelyTyped; Beispielcode, der nicht kompiliert werden kann:

/// <reference path="..." />

class Example<T extends IThingWithTitle<T>> {

    public test = (arg : T[]) : void => {
        _.sortBy(arg, (el : T) => { return el.title; }); // TS2686: '_' refers to a UMD global, but the current file is a module. Consider adding an import instead.
    };

}

export = Example;

(Bitte sagen Sie mir nicht, dass ich das Projekt auf den Kopf stellen muss. Ich weiß, dass wir in einigen Aspekten hinter der Kurve stehen.)

Update: ((window) ._) / * FIXME https://github.com/Microsoft/TypeScript/issues/10178 * /. sortBy (...) funktioniert, aber lieber Herr, es ist hässlich :-P

@ Gilead , die Lösung aus diesem Kommentar funktioniert vorerst einwandfrei: https://github.com/Microsoft/TypeScript/issues/10178#issuecomment -263030856

Gibt es hier Fortschritte? Ich habe einen Fall, in dem die erwähnte Problemumgehung nicht zu funktionieren scheint (mit [email protected] ), weil ich auf dieses Problem stoße.


Zuerst habe ich das versucht:

import 'firebase';

declare global {
  const firebase;
}

Dies gibt dem globalen firebase implizit den Typ any und wendet dann den Namespace (mit demselben Namen) darauf an. Zuerst schien dies zu funktionieren, da es die richtigen Tooltips / Intellisense für alle Tasten der obersten Ebene von firebase anzeigt.

Es funktioniert jedoch nicht wirklich (ich nehme an, weil es dann auf die Verwendung als Typ any umschaltet, was ein Fehler sein könnte?):


Also habe ich die hier erwähnte Problemumgehung ohne Erfolg versucht (es funktioniert jedoch für andere):

import _firebase from 'firebase'; // same with = require('firebase') 

declare global {
  const firebase: typeof _firebase;
}

=> 'firebase' wird direkt oder indirekt in einer eigenen Typanmerkung referenziert.
(obwohl der Namespace einen Alias ​​hat?)


Ich habe es auch versucht

import * as _firebase from 'firebase';

declare global {
  const firebase: typeof _firebase;
}

=> Zirkuläre Definition des Importalias '_firebase'.
(Vielleicht wegen export = firebase; export as namespace firebase; in seiner Definition ?)


Und schließlich, wenn ich nur die import 'firebase' mache, bin ich wieder da

'firebase' bezieht sich auf eine globale UMD, aber die aktuelle Datei ist ein Modul. [2686]


Wenn jemand eine Lösung dafür hat, wäre es sehr dankbar. Ansonsten scheint mir jeder der bisher erwähnten Lösungsvorschläge wirklich in Ordnung zu sein (Flag, dreifacher Schrägstrich, types in tsconfig, mit einem global oder external Objekt in tsconfig).

Zu @aluanhaddads Kommentar

Dies kann nicht zulassen, dass all dies in die Quere gekommen ist und zu den Globalen zurückkehrt!

Ich versuche nicht, zu Globals zurückzukehren, sondern nur ein paar starke Abhängigkeiten getrennt von meinem App-Bundle zu laden, während ich weiterhin Module für alles andere verwende, da dies einige Vorteile mit sich bringt: Die Abhängigkeiten können ordnungsgemäß zwischengespeichert werden weil sie nicht so oft aktualisiert werden wie mein App-Bundle; Meine Bundle-Größe explodiert nicht (manchmal enthält der Bundler aufgrund der Code-Aufteilung dieselbe Abhängigkeit mehrmals), was bedeutet, dass meine App-Benutzer weniger herunterladen müssen. Das Wiederherstellen meiner Bundles während der Entwicklung ist viel schneller.

Dies ist wirklich eine sehr einfach hinzuzufügende Funktion. Es wäre großartig für ein Community-Mitglied, es aufzunehmen.

@RyanCavanaugh Ich compiler/types.ts hinzufügen und den globalen Umd-Check in compiler/checker.ts ändern muss, und ich denke, ich muss ihn zu compiler/commandLineParser.ts hinzufügen

@simonhaenisch Sie können es in einer Nicht-Modul-Deklarationsdatei deklarieren. firebase wird als Namespace deklariert. Glücklicherweise erweitert es unsere Deklaration und verursacht keine Fehler.

// umd.d.ts
import firebase = require("firebase");
export import firebase = firebase;
export as namespace UMD;

// global.d.ts
declare const firebase: typeof UMD.firebase;

Leider haben wir einen Wert und keinen Namespace deklariert. Sie können also nicht so etwas wie let x: firebase.SomeInterface . Der einzige Weg, einen Namespace als Alias ​​zu verwenden, besteht darin, einen Import zu deklarieren, aber Sie können nicht declare import firebase = UMD.firebase; , weil der Namespace ihn nicht erweitert. Sicher, wir können einen anderen Namen nur für namspace verwenden, indem wir in type verwenden, aber das wird Verwirrung stiften. Ich würde lieber den Rest des oben erwähnten Codes löschen, ihn zur Laufzeit einem globalen Wert zuweisen und den Importalias wirklich funktionieren lassen.

Ähnlich wie im vorherigen Kommentar laden wir hls.js (UMD) und Referenztypen faul:

In hls.d.ts :

import * as Hls from 'hls.js';
declare global {
    const Hls: typeof Hls;
}

In der Datei .ts mit dem verzögert geladenen UMD-Modul:

/// <reference path="hls.d.ts" />
// now use it
if(Hls.isSupported()){
 ...
} 

Getestet in Typescript> = 3.0.1 und 3.4.1.

Grund dafür ist die unvollständige Browserunterstützung für dynamische Modulimporte.

@MatthiasHild Kann es ohne den Kommentar /// <reference path="hls.d.ts" /> ?

BEARBEITEN, ja, das kann es, solange sich die Deklaration in einer enthaltenen .d.ts -Datei befindet, die NICHT den gleichen Namen wie eine andere .ts -Datei hat, basierend auf dieser SO-Frage (das hat mich dazu gebracht und warum ich gefragt habe).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

dlaberge picture dlaberge  ·  3Kommentare

jbondc picture jbondc  ·  3Kommentare

Roam-Cooper picture Roam-Cooper  ·  3Kommentare

weswigham picture weswigham  ·  3Kommentare

blendsdk picture blendsdk  ·  3Kommentare