Typescript: Envisagez d'autoriser l'accès aux globaux UMD à partir des modules

Créé le 5 août 2016  ·  73Commentaires  ·  Source: microsoft/TypeScript

Les commentaires de # 7125 sont que certaines personnes mélangent et associent les bibliothèques UMD globales et importées, ce que nous n'avons pas considéré comme un scénario probable lors de la mise en œuvre de la fonctionnalité.

Trois options plausibles:

  1. Faites ce que nous faisons aujourd'hui - mauvais parce qu'il n'y a pas de bonne solution de contournement
  2. Permettez à une certaine syntaxe ou configuration de dire "cet UMD global est en fait disponible dans le monde entier" - quelque peu complexe, mais faisable
  3. Autoriser l'accès à tous les globaux UMD quel que soit le contexte - manque les erreurs où les gens oublient d'importer le global UMD dans un fichier. Ceux-ci sont probablement assez rares, mais il serait stupide de les manquer

On dirait que cela fonctionnerait mais ne le ferait probablement pas:

  1. Marquer les modules UMD importés comme "non disponibles pour le global" - incorrect car les modules UMD seront importés dans les fichiers de déclaration lors de l'augmentation du module. Ce serait étrange d'avoir un comportement différent des importations à partir des fichiers d'implémentation et des fichiers de déclaration.

Je suis enclin à l'option 3 par souci de simplicité, mais je pourrais voir l'option 2 s'il existe une syntaxe ou une configuration raisonnablement bonne que nous pourrions utiliser dans un endroit logique. Détecter l'utilisation d'un UMD global dans une règle TSLint serait simple si quelqu'un voulait le faire.

Une voie à suivre serait d'implémenter l'option 3 et s'il s'avère que les gens font souvent l'erreur "oublié d'importer", ajoutez une option tsconfig globals: [] qui spécifie explicitement quels globaux UMD sont autorisés.

Add a Flag Committed Suggestion good first issue help wanted

Commentaire le plus utile

+1 à ce sujet. J'essayais juste d'utiliser React avec SystemJS, et comme React ne se combine pas très bien, je le charge juste à partir du CDN dans une balise de script, et donc les objets React / ReactDOM sont disponibles dans le monde entier.

J'écris du code sous forme de modules en tant que meilleure pratique, mais cela sera regroupé (Rollup) dans un script d'exécution qui s'exécute à la charge. C'est une douleur (et un mensonge) d'avoir à import from react / react-dom, puis de configurer le chargeur pour dire "pas vraiment, ce sont des globaux" (similaire à l'exemple de configuration WebPack donné en https: / /www.typescriptlang.org/docs/handbook/react-&-webpack.html). Il serait beaucoup plus facile (et plus précis) de simplement les avoir disponibles sous forme de globaux dans mes modules. Les étapes que j'ai essayées, car elles semblaient intuitives, étaient:

  1. npm install --save-dev @types/react @types/react-dom
  2. Dans mon tsconfig.json: "jsx": "react", "types": ["react", "react-dom"]
  3. Dans mon module: export function MyComponent() { return <div>{"Hello, world"}</div>; }
  4. De même: ReactDOM.render(...)

Cependant, cela entraîne l'erreur React refers to a UMD global, but the current file is a module. Consider adding an import instead .

Si cela fonctionnait, ce serait beaucoup plus simple que de prétendre dans le code que c'est un module, puis de configurer le chargeur / bundler que ce n'est pas le cas. (Ou bien, je l'ai un peu réussi à faire ce que j'attendais en ajoutant un fichier contenant ce qui suit. Maintenant, mes modules peuvent utiliser React & ReactDOM comme globaux sans erreur, mais c'est un peu moche / hacky - bien qu'il puisse y avoir un moyen plus simple que je '' j'ai manqué):

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

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

Tous les 73 commentaires

Au lieu d'autoriser l'accès à tous les globaux UMD quel que soit le contexte, ne serait-il pas plus simple de n'autoriser l'accès au global UMD que si le module UMD a été explicitement "référencé" (non importé) via la syntaxe ///<reference types=<>> , ou via la configuration types dans tsconfig.json?

En d'autres termes, pourquoi ne pas simplement permettre l'utilisation de ///<reference types=<>> dans un module?

Si nous avons dit que /// <reference type="x" /> signifiait que x était globalement disponible _ partout_, il se produira souvent que certains fichiers .d.ts quelque part référenceront de manière incorrecte des choses qui ne sont pas vraiment globales ( Je peux vous dire cela parce que j'ai maintenu la branche 2.0 de DefinitelyTyped et c'est une erreur extrêmement courante).

Inversement, s'il n'est disponible que _dans ce fichier_, alors vous allez devoir copier et coller des directives de référence partout, ce qui est vraiment ennuyeux. Ces directives sont normalement idempotentes, donc introduire un comportement spécifique au fichier est bizarre.

Je vois. Eh bien, si cela n'affecte personne d'autre, il vaut peut-être mieux maintenir le comportement actuel. Je vais juste devoir passer complètement à l'importation de choses en tant que modules.

Edit: heureux de voir que cela affecte beaucoup de gens en plus de moi.

La théorie actuelle consiste simplement à demander aux gens de migrer vers l'utilisation de modules ou non. Si d'autres personnes rencontrent ce problème, veuillez laisser un commentaire avec exactement les bibliothèques que vous utilisiez afin que nous puissions enquêter davantage.

J'utilise lodash, qui ne vient pas avec ses propres typages. J'ai également une situation où dans mon environnement d'exécution, il est plus facile d'utiliser des instructions d'importation de chemin relatif. Donc, j'ai une combinaison d'instructions d'importation avec des chemins relatifs locaux et des parents de dossier ('./foo' ainsi que 'N / bar').

Si je copie manuellement @types/lodash/index.d.ts dans node_modules/lodash/ je peux faire vérifier le type de choses.

Jusqu'à présent, ma solution de contournement utilisait ///<amd-dependency path='../lodash' name="_"> (et aucune instruction import ). Avec ce combo, les définitions @ types / lodash seraient vues «globalement» par le compilateur et auraient toujours le chemin relatif correct ( ../lodash ) dans le JS émis.

J'espère que c'est un scénario assez proche de ce problème?

Pouvez-vous clarifier

J'ai également une situation où dans mon environnement d'exécution, il est plus facile d'utiliser des instructions d'importation de chemin relatif.

et

Si je copie manuellement @types/lodash/index.d.ts dans node_modules/lodash/ je peux faire vérifier le type de choses.

S'il vous plaît? Je ne suis pas familier avec ce scénario, alors quel est le but de ceci et pourquoi est-il utile?

Salut les gars,

Je suis en train de chercher une solution à courant @types/bluebird déclaration problème (s'il vous plaît ne pas passer du temps de le lire). J'ai trouvé que le problème pouvait être résolu en ajoutant export as namespace Promise; au .d.ts, mais je me suis ensuite heurté au problème décrit par ce problème github.

En bref, j'aimerais que ce qui suit fonctionne:

  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. Modifiez node_modules/@types/bluebird/index.d.ts en ajoutant export as namespace Promise; au-dessus de la ligne export = Bluebird; .
  5. npm run tsc

Résultat actuel:
Quelques erreurs 'Promise' refers to a UMD global, but the current file is a module. Consider adding an import instead. .

Résultat attendu:
La compilation réussit.

Ce problème est particulièrement difficile, car il est déclenché par l'utilisation de Promise à la fois dans le code de développement et dans le code tiers (RxJS dans ce cas). Ce dernier suppose que Promise est global (fourni par le standard JS), donc ne changera jamais pour utiliser par exemple import Promise from std; // (not that "std" is a thing) .

J'apprécierais vraiment un moyen d'utiliser les modules UMD en tant que modules importables et en tant que globals.

Merci.

----------------------------- Mettre à jour

J'ai fini par résoudre ce problème différemment (à savoir: par l'augmentation des interfaces Promise et PromiseConstructor ).

L'option "globals": [] tsconfig semble préférable à leur visibilité partout. Avec la déclaration UMD devenant la norme, les chances d'oublier accidentellement d'importer un module sont élevées. Veuillez envisager de conserver le comportement actuel. Cela devrait être une erreur.

De manière anecdotique, je me souviens quand le moment a supprimé leur variable globale window.moment dans une version intermédiaire. Nous pensions que nous l'avions importé judicieusement partout, mais nous avions oublié 5 endroits.

Bien sûr, un package UMD sera disponible dans la portée globale au moment de l'exécution, mais le moment où il deviendra disponible dépendra de l'ordre dans lequel les autres modules sont chargés.

+1 à ce sujet. J'essayais juste d'utiliser React avec SystemJS, et comme React ne se combine pas très bien, je le charge juste à partir du CDN dans une balise de script, et donc les objets React / ReactDOM sont disponibles dans le monde entier.

J'écris du code sous forme de modules en tant que meilleure pratique, mais cela sera regroupé (Rollup) dans un script d'exécution qui s'exécute à la charge. C'est une douleur (et un mensonge) d'avoir à import from react / react-dom, puis de configurer le chargeur pour dire "pas vraiment, ce sont des globaux" (similaire à l'exemple de configuration WebPack donné en https: / /www.typescriptlang.org/docs/handbook/react-&-webpack.html). Il serait beaucoup plus facile (et plus précis) de simplement les avoir disponibles sous forme de globaux dans mes modules. Les étapes que j'ai essayées, car elles semblaient intuitives, étaient:

  1. npm install --save-dev @types/react @types/react-dom
  2. Dans mon tsconfig.json: "jsx": "react", "types": ["react", "react-dom"]
  3. Dans mon module: export function MyComponent() { return <div>{"Hello, world"}</div>; }
  4. De même: ReactDOM.render(...)

Cependant, cela entraîne l'erreur React refers to a UMD global, but the current file is a module. Consider adding an import instead .

Si cela fonctionnait, ce serait beaucoup plus simple que de prétendre dans le code que c'est un module, puis de configurer le chargeur / bundler que ce n'est pas le cas. (Ou bien, je l'ai un peu réussi à faire ce que j'attendais en ajoutant un fichier contenant ce qui suit. Maintenant, mes modules peuvent utiliser React & ReactDOM comme globaux sans erreur, mais c'est un peu moche / hacky - bien qu'il puisse y avoir un moyen plus simple que je '' j'ai manqué):

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

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

Je suis également d'accord avec les options trois plus globales: [] sauvegarde. Cela semble assez intuitif pour les utilisateurs nouveaux et anciens et donnerait la fonctionnalité exacte dont les gens ont besoin.

Je ne suis pas un spécialiste du code donc je ne peux pas vraiment dire si 2 serait plus préférable ou non, mais je pense que ce serait aussi intuitif étant donné que la configuration est simple.

Si je voulais rechercher de l'aide pour mettre en œuvre l'un de ces éléments, où devrais-je aller?

Cela devrait vraiment être derrière un drapeau. C'est un danger de refactoring massif. Même si l'indicateur est spécifié par défaut sur true. Je pense que cela doit continuer à fonctionner dans le scénario d'origine, sinon nous perdons le principal avantage des déclarations UMD.

React ne se combine pas très bien

@billti pouvez-vous élaborer?

C'est pénible (et un mensonge) d'avoir à import from react / react-dom, puis de configurer le chargeur pour dire "pas vraiment, ce sont des globaux"

La seule raison pour laquelle j'ai écrit cela dans le tutoriel est que l'utilisation de externals réduit le temps de bundle. Si vous utilisez la variable globale React sans importer, vous ne pouvez pas facilement passer aux modules plus tard, alors que les importations vous donnent la flexibilité d'utiliser l'un ou l'autre compte tenu de votre chargeur.

Consultez ce numéro (https://github.com/rollup/rollup/issues/855) pour un exemple sur la façon dont ils essaient d'optimiser le regroupement et les tailles observées. En fait, dans ma configuration (en utilisant Rollup), j'ai vu des gains de taille minimaux regrouper React, donc je préfère simplement le servir à partir d'un CDN. Pour moi, cela a les avantages de:

a) Moins de requêtes (et de bande passante) sur mon site.
b) Moins de temps à regrouper dans ma chaîne de construction.
c) Moins de code à retélécharger sur le client à chaque fois que je pousse un changement (car seul mon code est dans le bundle qui est re-téléchargé, et React est toujours dans le cache client non modifié - obtenant ainsi 304s).

En regardant dans les outils de développement Chrome lors du chargement du site, React et React-dom (les versions minifiées), sur une connexion HTTP GZipped, ne représentent que 47 ko de trafic réseau, ce qui est inférieur à la plupart des images sur un site, donc je ne suis pas inquiets d'essayer de réduire autant de toute façon, à moins qu'il y ait vraiment de gros gains à réaliser (par exemple une réduction de 50%).

En complément: je noterais également que sans cette option, vous obligez également les gens à utiliser un bundler qui élide ces importations, car le compilateur TypeScript lui-même n'a pas de configuration pour dire "ce module est vraiment un global", et sera donc émettre des importations (ou requiert, ou définit) pour les modules qui ne résoudraient pas lors de l'exécution.

@billti SystemJS prend entièrement en charge ce scénario. Vous pouvez basculer entre l'utilisation d'un package installé localement pendant le développement et l'utilisation d'un CDN en production. Il a également un support complet pour les métadonnées qui spécifie que toutes les importations doivent en fait indiquer des références à une variable globale qui sera récupérée une fois et attachée à l'objet window lors de la première utilisation, en production cela peut provenir d'un CDN. Je ne l'ai pas fait avec react mais je l'ai fait avec angular 1.x

Merci @aluanhaddad . Intéressant ... J'essayais en fait de faire fonctionner quelque chose de similaire qui m'a conduit à ce barrage routier, et je n'ai pas pu le comprendre, alors ce matin, j'ai posé la question sur le repo SystemJS. Si vous pouvez répondre comment atteindre https://github.com/systemjs/systemjs/issues/1510, ce serait vraiment utile :-)

Remarque: Mon autre commentaire tient toujours, que l'émission par TypeScript lui-même n'est pas utilisable sans cela, car vous avez besoin de quelque chose comme SystemJS / WebPack / Rollup etc ... pour mapper les importations aux globals pour que le code s'exécute.

Je vais jeter un œil et voir si je peux faire un exemple fonctionnel, je ne l'ai pas fait depuis un bon moment et je n'ai pas accès au code source que j'avais à l'époque mais je suis sûr à cent pour cent c'est possible.

Pour votre deuxième point, c'est exactement ce que fait SystemJS. Il mappera ces importations au global et comprend que le global est en fait demandé et a déjà été chargé. La sortie est définitivement utilisable

FYI: J'ai fait fonctionner cela dans SystemJS en utilisant l'API SystemJS et j'ai ajouté ma solution sur https://github.com/systemjs/systemjs/issues/1510 . Merci.

Concernant mon deuxième point: oui, je sais que c'est exactement ce que les chargeurs peuvent faire. C'est mon point, ils peuvent mapper un module importé à un global, mais TypeScript ne peut pas - vous devez donc utiliser un chargeur pour rendre votre code valide au moment de l'exécution. C'est donc un catch-22 avec ce problème d'origine, où vous ne pouvez pas déclarer que le global (dans ce cas React) est disponible dans le module, vous devez l'importer comme s'il s'agissait d'un module (ce qui n'est pas le cas) .

Mon autre commentaire tient toujours, que l'émission par TypeScript lui-même n'est pas utilisable sans cela, car vous avez besoin de quelque chose comme SystemJS / WebPack / Rollup etc ... pour mapper les importations aux globals pour que le code s'exécute.

@billti je ne comprends pas. Quel est le scénario dans lequel votre seule option est d'utiliser la version globale d'un module, mais TypeScript ne vous permet pas de le faire? Je n'ai vu que des scénarios où une bibliothèque est disponible à la fois en

@DanielRosenwasser Je pense qu'il veut dire que React est en fait un global au moment de l'exécution comme dans un membre de l'objet global, à cause de la façon dont il est chargé.

@billti Génial que vous l'ayez fait fonctionner.

Re votre deuxième point: je vois ce que vous voulez dire.

Je suppose que mon sentiment est que, dans un scénario de navigateur, parce que vous devez utiliser un chargeur comme RequireJS ou un packager comme Webpack car aucun navigateur ne prend en charge les modules mais cela ne fait aucune différence. (J'entends que Chakra l'a disponible derrière un drapeau). Il n'y a donc aucun moyen d'exécuter le code sans un outil supplémentaire. C'est en quelque sorte une implication de la sortie contenant define , require , ou System.register que le code _JavaScript_ émis n'est pas susceptible d'être portable. Cependant, je vois l'importance de la distinction «module vs pas un module».

Vous pouvez utiliser cette solution de contournement pour au moins ne faire référence au «module» qu'une seule fois.

_shims.d.ts_

import __React from 'react';

declare global {
  const React: typeof __React;
}

Ensuite, vous pouvez l'utiliser n'importe où ailleurs sans l'importer.
De plus, c'est bien explicite, même si c'est un peu bavard, car vous dites que React est devenu mondial et c'est aussi la raison pour laquelle vous n'avez plus à l'importer.

Concernant vos shims.d.ts, si vous montez quelques articles, vous verrez que c'est ce que j'ai fait pour le moment (les grands esprits pensent pareil) ;-)

Je peux le faire fonctionner de plusieurs façons maintenant, ce n'est pas le but. Nous essayons de rendre TypeScript facile à adopter et de faire tomber les utilisateurs dans le gouffre du succès, pas dans le gouffre du désespoir. Dans cet esprit, je me pose souvent deux questions en essayant d'utiliser TypeScript et en rencontrant des problèmes: a) Ce code est-il valide, et b) Les clients vont-ils essayer de le faire?

Étant donné que j'avais la version (non-TypeScript) qui faisait ce que je voulais dans Babel à peu près le temps qu'il me fallait pour la taper, je pense qu'il est juste de dire que le code est valide. Comme la page d'installation des documents React montre comment utiliser les balises de script d'un CDN pour inclure React, j'imagine qu'un certain nombre de personnes essaieront également cela. (FWIW: j'ai passé plus de temps que je ne m'en souviens à travailler avec divers modules et chargeurs JS, donc ce n'est pas comme si je ne les connaissais pas, je voulais juste écrire mon code de cette façon).

Si TypeScript ne prend pas en charge certains modèles valides d'écriture de code, nous devrions essayer de rendre cela immédiatement évident et orienter les gens vers la droite (ce qui est un défi à faire dans les messages d'erreur ou les documents concis). Mais personnellement, je ne pense pas que TypeScript ne devrait pas prendre en charge les modèles parce que nous ne pensons pas qu'ils soient des "meilleures pratiques" ou "canoniques". Si le code est valide et que certains développeurs JavaScript peuvent vouloir l'écrire, alors TypeScript devrait essayer de le prendre en charge. Plus nous exigeons qu'ils modifient leur code et reconfigurent leur pipeline de construction pour que TypeScript fonctionne (comme cela est recommandé ici pour migrer mon application triviale), moins les développeurs se déplaceront.

Quant à la solution ... il suffit de cracher ici, mais peut-être que l'option du compilateur "lib", qui définit déjà efficacement quelles API sont disponibles dans tout le projet, pourrait également prendre des valeurs de format @types/name pour que les bibliothèques ajoutent globalement (et peut-être même prendre en charge les chemins relatifs).

Nous essayons de rendre TypeScript facile à adopter et de faire tomber les utilisateurs dans le gouffre du succès, pas dans le gouffre du désespoir.

Je pense que nous essayons de diriger les utilisateurs vers la fosse de succès en ce moment. Si un module ne définit que conditionnellement un global, alors vous guidez accidentellement les utilisateurs vers l'utilisation de quelque chose qui n'existe pas. Je vois donc quelques options différentes:

  1. Créez une construction export as namespace foo augmentée qui n'est visible que si elle n'est pas importée par un module.
  2. Ne faites rien et continuez à pousser les gens à utiliser l'importation - c'est plus ou moins bien à mon avis, car nous avons de toute façon rendu le message d'erreur raisonnablement prescriptif.
  3. Permettre aux gens d'utiliser l'UMD de partout - honnêtement, je ne suis pas aussi fan de cette idée.

@billti

Concernant vos shims.d.ts, si vous montez quelques articles, vous verrez que c'est ce que j'ai fait pour le moment (les grands esprits pensent pareil) ;-)

Désolé, j'ai raté ça, très gentil;)

Je ne pense pas que TypeScript ne devrait pas prendre en charge les modèles parce que nous ne pensons pas qu'il s'agit de "meilleures pratiques" ou "canoniques"

Je ne pense pas que TypeScript soit proscriptif ici, je pense qu'il fait ce qu'il prétend, en me disant que j'ai une erreur. De nombreuses bibliothèques proposent des démos et des didacticiels dans lesquels elles se chargent elles-mêmes en tant que globales, puis utilisent la syntaxe du module ES. Je ne pense pas qu'ils soient les plus grands citoyens en faisant cela, mais c'est une autre discussion.

Cela dit, si les modules sont principalement utilisés comme sucre syntaxique _ perçu_ par rapport aux globaux, leur échec est à portée de main car ils ne sont pas du tout un sucre syntaxique. Si quoi que ce soit, il s'agit d'un sel syntaxique (peut-être une taxe?) Que nous consommons pour des avantages tels que la véritable isolation du code, la liberté de l'ordonnancement des balises de script, la déclaration de dépendance explicite, la sortie de l'enfer global des espaces de noms et d'autres avantages. La syntaxe des modules n'est pas ergonomique, elle est au mieux verbeuse, mais c'est la sémantique des modules qui en vaut la peine.

Je pense que si les gens utilisent TypeScript, au moins dans des fichiers .ts , je suppose qu'ils veulent profiter des avantages d'une analyse de code statique solide. Babel ne fait pas cela, en supposant que React existe mais n'en ayant aucune connaissance. Cela est vrai même si les modules ES ont été délibérément spécifiés pour se prêter à une analyse statique.

@DanielRosenwasser

Créez une exportation augmentée en tant que construction d'espace de noms foo qui n'est visible que si elle n'est pas importée par un module.

Cela semble être la meilleure façon de résoudre ce problème.

Voici un autre cas où cela a causé des problèmes:

Dans un projet sur lequel je travaille actuellement, nous mélangons des inclusions locales (principalement pour des raisons historiques) avec des modules npm. En fin de compte, tout est joint en utilisant Rollup ou Browserify, donc ça va.

J'utilise un fichier .js du projet emojione que j'ai simplement copié dans la base de code. Plus tard, j'ai ajouté les déclarations de type pour cela à DefinitelyTyped: https://github.com/DefinatelyTyped/DefinatelyTyped/pull/13293 Je pensais que je pouvais maintenant simplement charger les types et tout fonctionnerait. Mais cela ne semble pas être le cas, car TypeScript ne me permettra pas d'accéder au global.

La raison pour laquelle je ne passe pas au module npm est que le module npm regroupe également plusieurs mégaoctets de sprites et de PNG. J'ai juste besoin de ce script de 200 Ko. Avec des déclarations de type.

Avec AngularJS, la solution de contournement était declare var angular: ng.IAngularStatic . Mais cela ne fonctionne pas avec les espaces de noms, non?

@dbrgn Vous rencontrez un problème différent. Si le module est en fait un module global, votre définition de type est incorrecte. Il ne déclare ni une déclaration globale, ni une déclaration de style UMD (il s'agit de déclarations de style UMD), il déclare en fait un module ES pur uniquement.

Si le module représente un global, n'exportez pas au niveau supérieur du fichier, cela en fait un module.

Avec AngularJS, la solution de contournement était de déclarer var angular: ng.IAngularStatic. Mais cela ne fonctionne pas avec les espaces de noms, non?

Cela fonctionne avec les espaces de noms.

Le résultat de la discussion lors de notre réunion de conception a été que nous envisageons de toujours autoriser l'UMD et d'ajouter un indicateur qui applique la restriction actuelle. La restriction sera également étendue pour fonctionner sur l'accès aux types à partir d'un UMD global.

Après avoir réfléchi davantage à cela, je pense toujours que la meilleure chose à faire est de créer un nouveau type de déclaration. Cet indicateur est moins découvrable que la nouvelle syntaxe, qui n'a besoin d'être écrite qu'une seule fois par l'auteur du fichier de déclaration.

Ceci est désespérément nécessaire pour le code et les outils existants. Jusqu'à ce que Javascript cesse de jouer rapidement et perd avec les systèmes de modules, nous avons besoin de flexibilité pour travailler avec le code tel qu'il existe. Émettez un avertissement, mais n'échouez pas la construction. J'ai perdu des jours à faire en sorte que le code hérité joue bien avec le rollup et le tapuscrit.

POUAH.

Je sais qu'il y a beaucoup de gens qui aiment rire de Java, mais les modules Java de base fonctionnent au moins. Les pots fonctionnent

Je n'ai pas besoin de s'adapter à 14 normes de module ad hoc différentes, ou d'essayer de compiler un module js à partir de fichiers source dans le format que l'outil de cumul / regroupement du jour consommera réellement sans caca, et générera également un format de module qui jouera bien avec les instructions d'importation / exportation Typescript et les fichiers d.ts tiers afin que TSC décide réellement de créer le code au lieu de se plaindre de quelque chose où vous allez "UTILISEZ JUSTE L'IMPORTATION DARN, CE SERA UN GLOBAL À DURÉE".

Le hack shims.d.ts fonctionne bien. Mais pouah.

Solution temporaire pour ceux qui utilisent Webpack https://github.com/Microsoft/TypeScript/issues/11108#issuecomment -285356313

Ajoutez externals à webpack.config.js avec les globaux UMD souhaités.

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

Je pense que cela devrait être possible pour faciliter la migration des bases de code existantes.

J'ai un projet implémenté avec requirejs où jQuery est inclus comme global, car il existe des plugins qui étendent jQuery uniquement s'il est trouvé en tant que global.

Le code de certains modules dépend de ces plugins, qui ne seraient pas disponibles si jQuery était importé en tant que module. Pour faire ce travail, je devrais modifier tous les plugins pour qu'ils fonctionnent avec jQuery chargé en tant que module, en les chargeant également en tant que modules (en devinant où ils sont nécessaires).

En outre, il existe également des pages qui utilisent javascript sans chargeur de module. Ainsi, les plugins devraient fonctionner à la fois avec les globaux et les modules.

En dehors de jQuery, il existe d'autres scripts avec le même problème comme knockout et d'autres. Cela fait de la migration du projet un nitghtmare. Ou, d'un point de vue réaliste, irréalisable.

Bien sûr, ce n'est pas le meilleur modèle et je ne l'utiliserais pas dans un nouveau projet. Mais je ne pense pas que je suis le seul à avoir ce problème

Serait-il judicieux d'utiliser types dans tsconfig.json pour cela? Par exemple, sans types set, vous obtenez le comportement implicite actuel et avec types set, vous dites littéralement "ces choses sont globales" et pouvez forcer l'espace de noms UMD à apparaître globalement. C'est le genre de comportement qui existe aujourd'hui de toute façon (moins la force globale). Cela s'oppose à l'introduction d'une nouvelle option globals .

Je pense que c'est une bonne idée. Dans mon cas, il existe des scripts qui utilisent une bibliothèque UMD comme globale et d'autres comme module. Je pourrais résoudre ce problème avec deux tsconfig.json différents qui traitent chaque cas. Vraiment droit.

@blakeembrey Bien que l'utilisation de types sens, je ne suis pas trop enthousiaste à l'idée de la surcharger car elle a déjà des problèmes. Par exemple, la construction <reference types="package" /> a déjà la limitation qu'elle ne prend pas en charge "paths" . Le "package" doit renvoyer à un nom de dossier dans @types

J'ai du mal à suivre cette conversation. Y a-t-il eu des mises à jour ou des résolutions prévues à ce sujet? Il semble que ce soit quelque chose qui pourrait être utile dans des scénarios tels que lorsque lodash fait partie intégrante d'une application, ou lorsque davantage de bibliothèques tierces se convertissent en une structure plus modulaire au lieu de se fier uniquement à la fenêtre.

Existe-t-il un moyen prévu de résoudre ce problème ou du moins de documenter comment cela devrait être résolu avec la version actuelle disponible?

Salut @mochawich J'obtiens l'erreur suivante en utilisant la définition de React en tant qu'externe et sans utiliser la syntaxe declare global :

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

@cantux TypeScript ne lit pas la configuration de Webpack. Si vous avez rendu React disponible dans le monde entier, vous pouvez declare cela, mais pourquoi ne pas utiliser des modules?

@aluanhaddad principalement parce que j'étais confus avec le travail effectué par appel d'importation. J'en ai tripoté, les affirmations suivantes sont-elles correctes?

Nous payons les frais minimes pour faire une demande lorsque nous importons un module. Cela garantit que ce que nous utilisons est disponible dans la mémoire, s'il a été précédemment demandé, le module est chargé à partir du cache, si le module n'existe pas, il est récupéré. Si vous souhaitez contourner cette demande, vous définissez simplement quelque chose comme global et Typescript vous fait confiance aveuglément qu'il est disponible (et si vous utilisez un bundler intelligent, les instructions d'importation peuvent même être remplacées / supprimées).

Si ceux-ci sont corrects, nous pourrions supprimer les commentaires par souci de concision, le fil est un géant tel quel.

Comme @codymullins l'a demandé ci-dessus, quelqu'un peut-il résumer la solution de contournement actuelle pour ce problème? Je viens de mettre à jour la définition du type lodash et j'ai beaucoup d'erreurs TS2686.

Ma solution de contournement actuelle était de pirater le fichier typedef pour se conformer à l'ancienne norme de travail, mais ce n'est pas viable si plus de fichiers typedef commencent à se casser.

Mon scénario est le suivant:

  • dans mes applications d'une seule page, j'importe un certain nombre de bibliothèques (y compris lodash) dans un

l'exemple de shim mentionné ci-dessus fonctionne, bien que vscode le met en évidence comme une erreur (même s'il effectue toujours correctement la complétion!)

Merci de ne pas donner d'erreurs lors de l'accès aux globaux UMD dans les modules. Le projet massif sur lequel je travaille est réalisé dans AngularJS et nous utilisons Typescript pour l'application, mais bien sûr, nous avons besoin de Typescript pour connaître les types globaux et angulaires angular UMD à partir de @types/angular . On pourrait penser que ce serait aussi simple que d'ajouter "angular" à types dans tsconfig.json , mais, pour une raison quelconque, ce n'est pas le cas, et TSC me crie dessus. Autant je souhaiterais que tous les packages NPM soient de purs Typescript, la plupart d'entre eux sont de simples JS et le seront pour très longtemps. Je ne comprends vraiment pas pourquoi TSC ne peut pas simplement se taire lorsque nous importons un d.ts disant qu'un UMD global est présent. Cette situation est plus que courante - chaque projet Typescript sur lequel j'ai travaillé utilise au moins une bibliothèque JS que je dois regrouper moi-même et référencer en utilisant des définitions de type.

Y a-t-il une mise à jour à ce sujet?

Mon cas d'utilisation: je travaille sur une grande base de code existante qui fait un usage intensif des CDN. Les utilitaires courants sont importés via des balises de script sur de nombreuses pages (ex. Clipboardjs, lodash). Je voudrais faire référence à ces variables globales puisqu'elles sont disponibles sur la page. Sans utiliser de modules, il est assez facile d'avoir une compilation dactylographiée, en utilisant /// <reference type="$name" /> en haut des fichiers source pertinents. Cependant, cela cesse de fonctionner lorsque vous essayez de créer des modules.

Il semble que deux approches ont été proposées dans le fil:

  1. Avoir les jetons d'importation /// <reference type="$name" /> uniquement dans l'espace de noms du fichier actuel.

  2. Une option / variable de configuration du compilateur dans tsconfig.json (ex. "globals" , "types" )

Je pense que les deux approches sont bonnes. Bien que je sois d'accord avec la critique de l'option 1 par @RyanCavanaugh :

Inversement, s'il n'est disponible que dans ce fichier, vous allez devoir copier et coller des directives de référence partout, ce qui est vraiment ennuyeux.

Je pense que c'est beaucoup plus ennuyeux que vous ne puissiez pas du tout utiliser des modules avec des globaux UMD en raison du comportement actuel. Une solution de contournement est préférable à aucune.

Ce problème est-il toujours en suspens? Et si oui, quelle est la solution de contournement actuelle?

Si vous installez le package @types , les packages qui ne sont pas importés en tant que modules sont rendus disponibles en tant que globals.

Par exemple, si je npm install -D @types/underscore à la racine de mon projet, alors je peux écrire des modules qui n'importent rien du trait de soulignement, mais le _ global est rendu disponible (voir ci-dessous).

types-ref

C'est ce que vous recherchez?

@billti Peut-être que je ne comprends pas bien, mais votre exemple ne fonctionne pas pour moi.

Minimal nécessaire pour 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"
    ]
}

Messages d'erreur:

js / foo.ts (7,3): erreur TS2686: «Cookies» fait référence à un global UMD, mais le fichier actuel est un module. Envisagez plutôt d'ajouter une importation.
js / foo.ts (10,15): erreur TS2686: «Cookies» fait référence à un global UMD, mais le fichier actuel est un module. Envisagez plutôt d'ajouter une importation.
js / foo.ts (15,14): erreur TS2686: «Cookies» fait référence à un global UMD, mais le fichier actuel est un module. Envisagez plutôt d'ajouter une importation.

Le comportement que vous obtenez dépend du fait que le module importé a été écrit comme un module UMD "approprié" (c'est le comportement avec "Cookies") ou un module "fonctionne dans les deux sens en même temps" (c'est ainsi que lodash est écrit) .

L'incohérence des gens qui écrivent correctement un fichier .d.ts qui décrit le fonctionnement de l'objet au moment de l'exécution, et l'opacité de l'expérience pour les développeurs, c'est pourquoi je me penche assez fort dans le sens "supprimer la restriction globale UMD". Nous pourrions le mettre sous --strict avec un opt-out --noStrictUMD .

L'autre chose que j'ai rencontrée concernait le chargeur AMD personnalisé de Monaco. Ils prennent en charge un sous-ensemble de comportement AMD (insérez un énorme eyeroll) mais piétinent le global `` require '', il est donc vraiment difficile d'utiliser des modules UMD appropriés avec lui, car ces modules ont tendance à voir le `` require '' global et à ne pas se charger correctement dans le Chargeur de modules Monaco. Vous finissez par mettre les bibliothèques UMD JS au-dessus de la balise de script pour le chargeur Monaco, puis TS se plaint parce que vous accédez aux globaux à partir d'un module (ce que vous devez être pour importer les API Monaco).

@RyanCavanaugh

L'autre chose que j'ai rencontrée concernait le chargeur AMD personnalisé de Monaco. Ils prennent en charge un sous-ensemble de comportement AMD (insérez un énorme eyeroll) mais piétinent le global `` require '', il est donc vraiment difficile d'utiliser des modules UMD appropriés avec lui, car ces modules ont tendance à voir le `` require '' global et à ne pas se charger correctement Chargeur de modules Monaco.

😁

Y a-t-il une chance qu'ils réparent ça?

J'ai beaucoup réfléchi au coût de complexité des modules ces derniers temps. Tant de chargeurs, de bundlers, de transpilers, de gestionnaires de packages et de frameworks interdépendants et partiellement compatibles représentent une complexité d'accréditation vraiment non négligeable. (Je suis sûr que vous n'avez besoin d'aucun rappel 🙉).

En tant que développeurs, nous avons accepté des chaînes d'outils qui sont des ordres de grandeur plus complexes qu'il y a 5-6 ans, et la principale source de complexité a été les modules.

Si nous abandonnons et commençons à charger ces packages UMD en tant que globaux, à quoi cela sert-il?

Et pourtant ... les gens font juste ça. C'est terrible!

Je veux dire, cette réponse Stack Overflow a 61 👍s et elle a suggéré toutes les mauvaises choses pour 99% des paquets au cours du dernier semestre. (l'auteur l'a gentiment mis à jour pour mentionner les modules comme une _option_ pour les dépendances UMD en raison de certains commentaires fournis ce matin)

Cela ne peut pas laisser tout cela être dans la veine et revenir aux globaux!

Et pourtant ... les gens font juste ça. C'est terrible!

Le problème est que les modules JS sont terriblement mal conçus et mis en œuvre, il est donc beaucoup mieux et plus facile de revenir à l'utilisation de globals. Si les modules avaient été correctement conçus et mis en œuvre dès le début ...

Nous combinons des modules et des globaux UMD parce que c'est beaucoup trop compliqué de charger nos dépendances en tant que modules avec différents niveaux de compatibilité avec divers chargeurs et certains chargeurs ne prenant pas en charge le regroupement direct de dépendances et à la place, vous devez utiliser notre préprocesseur spécial qui prend un minute pour courir.

Cette "fonctionnalité" signifie simplement que nous n'utilisons pas le support officiel du module UMD même si nous utilisons réellement des modules UMD. Nous exportons simplement en tant que fichier global à partir du fichier .d.ts, puis avons manuellement notre propre module de ce nom qui réexporte tout.

Une mise à jour pour ceci? J'aimerais vraiment que l'option 2 fonctionne:

Permettez à une certaine syntaxe ou configuration de dire "cette UMD globale est réellement disponible dans le monde entier"

Cela n'aide pas non plus qu'il y ait autant de bibliothèques js de style old-school
là, et les réécrire tous est hors de question. Je travaille juste sur un solide
config pour que Rollup les gère tous correctement gaspille des heures de mon temps.

Les gens se moquent de "Enterprise Java", mais Java simple est livré avec un
système de module à 1.0. Ce n'était pas parfait, mais ce n'était pas un désordre complet.

En l'état, "Autoriser les globaux de style UMD" devrait certainement être une option.

Le lun.2 avril 2018 à 01:40 Kagami Sascha Rosylight <
[email protected]> a écrit:

J'ai dû contourner le problème avec:

/ * module: es2015 * /
// js-yaml prend en charge UMD mais pas le module ES2015! import * as _jsyaml from "js-yaml"; declare var jsyaml: typeof _jsyaml; jsyaml.safeLoad ("");

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/10178#issuecomment-377885832 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AA50ljAD33sr09EGFVAsURbu1x75X-lOks5tkeQCgaJpZM4Jd8jX
.

>

Daniel Joyce

Les doux hériteront de la Terre, car les braves seront parmi les étoiles.

J'utilise three.js dans un projet Angular. Je l'importe comme

import * as THREE from "three";

import {Vector3} from "three"; fonctionne également comme prévu.

Avec les packages three et @types/three npm installés, tout fonctionne correctement. Sous le capot, je suppose que cela utilise three/build/three.module.js . Le fichier @types/three/index.d.ts utilise la notation export as namespace THREE , avec laquelle je ne suis pas tout à fait à l'aise, mais bon ça marche.

Dans ce cas particulier, le problème est qu'il existe un autre fichier associé dans le système three.js appelé OrbitControls.js (qui vous permet de faire pivoter des images 3D avec votre doigt ou votre souris, en gros). Le problème est que bien que cette fonction fasse semi-officiellement partie de la distribution three.js, il s'agit d'un ancien fichier JS trouvé dans l'arbre examples et se place directement sur la propriété THREE de la fenêtre, et utilise directement d'autres API qu'elle s'attend à trouver présentes sur window.THREE . Donc même si je "demande" le fichier avec

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

il ne trouve pas window.THREE pour se mettre en place ou pour accéder à d'autres parties du système THREE qu'il utilise. Je peux inclure la bibliothèque entière directement en utilisant la propriété Angular scripts dans angular.json (à peu près équivalent à une balise <script> à l'ancienne), mais si je ne me trompe pas, je aura chargé la bibliothèque deux fois.

Pour éviter cela, j'ai supprimé l'instruction import * as THREE from "three"; , et bon, il peut toujours résoudre des types tels que foo: THREE.Vector3 , mais s'étouffe sur des références comme new THREE.Vector3() avec le tristement célèbre

«THREE» fait référence à un UMD global, mais le fichier actuel est un module. Envisagez plutôt d'ajouter une importation. [2686]

À ce stade, je pense que je vais juste devoir récupérer le fichier OrbitControls.js et ES6-ify et / ou TS-ify, ce qui semble que plus d'une autre personne ait déjà fait sous la forme de choses comme `orbit-controls-es6 , alors peut-être que je devrais simplement simplifier ma vie et l'utiliser, même si je déteste mettre ma vie entre les mains des autres de cette façon.

Sur une note semi-indépendante, une bizarrerie est que @types/three définit des types pour OrbitControls , même si le code lui-même n'est pas dans le module three lui-même. Cependant, je ne peux pas comprendre comment associer tous ces types définissant une classe appelée OrbitControls avec quoi que ce soit - je voudrais déclarer que l'exportation par défaut du orbit-controls-es6 mentionné ci-dessus est de ce type, mais comment le faire m'échappe.

La solution que j'ai finalement trouvée, dont j'ai profondément honte, est:

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

Cela fonctionne, même si je ne sais pas pourquoi. Le fichier requis a une ligne telle que

THREE.OrbitControls = funtion() { };

ce qui semble finir par être assigné aux TROIS «espaces de noms» résultant de l'instruction import * as THREE from "three"; , ce qui ne devrait pas fonctionner, n'est-ce pas?

@RyanCavanaugh m'a demandé de copier mes commentaires de # 26223 ici:

Je maintiens une base de code TypeScript assez grande (monorepo interne de Google) qui contient plusieurs bibliothèques définitivement typées dont les gens dépendent. À l'origine, les utilisateurs se basaient uniquement sur des types globaux pour des bibliothèques telles que angular , avant que les .d.ts soient transformés en modules externes. Nous avons ensuite migré la base de code pour utiliser des modules et des importations explicites. Nous nous attendions en fait à ce que les globaux UMD export as namespace d nécessitent toujours une importation explicite pour utiliser des symboles, à la fois pour les références de type et de valeur, et nous n'avons même pas remarqué lorsque nous avons migré (oups).

Autoriser l'utilisation de code non importé est généralement problématique pour nous:

  • cela signifie que le code repose sur des définitions de type globales "d'arrière-plan", ce qui rend le code plus difficile à lire (en particulier dans les navigateurs de dépôt ou la révision de code sans aller au symbole).

  • il masque les dépendances du code

  • il contourne les contraintes "doit avoir une dépendance explicite au niveau de construction sur toutes les importations" que nous implémentons dans bazel, alias "strict deps".

    Dans une base de code volumineuse, votre code doit avoir des dépendances explicites, sinon le dépôt devient ingérable. Maintenant, si vous avez une dépendance chaing A -> B -> C et des types globaux, il est facile de faire compiler le code A simplement parce que B a une dépendance sur C . Si B supprime plus tard sa dépendance, il casse A , ce qui signifie que les modifications ont un effet d'entraînement inattendu sur le référentiel, violant l'isolation du code.

  • cela fait que le code importe de manière incohérente le module avec un préfixe pour les valeurs et utilise ses types avec un autre préfixe (en particulier pour AngularJS, ng vs angular)

Nous pouvons contourner ce problème en supprimant ces instructions export as namespace dans notre copie vendue de DefinatelyTyped, mais au moins pour nous, cette fonctionnalité est en quelque sorte contre la maintenabilité du code et nos objectifs d'ingénierie. Je pense que les problèmes sont plus prononcés dans une situation monorepo comme Google, mais s'appliquent généralement aussi dans des bases de code plus petites.

Les points que vous avez publiés sont absolument sans importance pour notre situation. Nous sommes obligés d'implémenter notre propre code avec des modules AMD et de fournir à nos dépendances des modules UMD en raison de circonstances qui sont largement hors de notre contrôle (mais je résumerais que les modules JS sont horriblement défectueux à la fois dans le concept et dans la mise en œuvre). Cette fonctionnalité nous permettrait de simplifier considérablement nos vies.

Peut-être qu'avec TS3, nous pourrions trouver comment éviter cela, mais même si nous le faisions, il faudrait probablement au moins deux ans avant que nous ayons terminé tous les changements nécessaires, ce serait donc toujours une fonctionnalité très utile pour nous.

Question ouverte: un indicateur global pour "Autoriser l'accès à tous les modules UMD" serait-il suffisant, ou les utilisateurs ont-ils vraiment besoin d'un contrôle par module sur l'erreur?

Votez ❤️ pour "juste un drapeau"
Votez 🎉 pour "besoin de contrôle par module"

J'étais également en train de considérer si la présence d'une liste explicite dans l'option "types" dans tsconfig.json ne devrait pas également permettre l'utilisation d'UMD dans un module. Cela signifie que le type est délibérément présent. (Bien que cela n'empêche évidemment pas l'erreur que vous avez oublié de l'importer).

Ou de la même manière, utiliser une construction /// <reference types="..." /> devrait permettre l'utilisation UMD de ce paquet dans le module dans lequel il est utilisé (c'est-à-dire le 'contrôle par module' mentionné).

@RyanCavanaugh Y

26233 est considéré comme fonctionnant pleinement comme prévu; l'accès au côté type d'un UMD global à partir d'un module est légitimement inoffensif

Je ne suis pas sûr qu'il soit «légitimement inoffensif». En utilisant @types/jquery comme exemple. $ et jQuery sont mappés à l'interface JQueryStatic et exportés sous forme de constantes. En conséquence, tous les modules peuvent accéder à $ et jQuery sans importation. J'espère pouvoir désactiver cela.

@RyanCavanaugh oui, c'est inoffensif dans le sens où l'émission TS n'est pas affectée par elle. C'est problématique si vous voulez un contrôle fin sur ce @types quoi

En fait, dans le cas de jQuery, l'émission est affectée. $() est émis dans un module sans importation.

Accepter les PR pour un nouveau drapeau qui permet d'accéder aux globaux UMD à partir de tous les modules.

Du point de vue de la mise en œuvre, c'est assez simple ... mais nous devons le nommer. Nous avons lancé une douzaine de noms terribles lors de la réunion d'examen des suggestions et nous les avons tous détestés, c'est donc à vous de trouver quelque chose de acceptable. Veuillez halp.

Nous avons lancé une douzaine de noms terribles lors de la réunion d'examen des suggestions et nous les avons tous détestés

Qu'étaient-t-ils?

c'est donc à vous de trouver quelque chose de acceptable.

Peut-être umdUseGlobal ou quelque chose.

Je suggérerais importAllNamespaces pour le nom du drapeau global UMD car les globaux UMD sont généralement export as namespace .

@RyanCavanaugh L'équipe a-t-elle discuté du problème de type?

@FranklinWhale oui.

@saschanaz J'ai déjà @RyanCavanaugh Vous

Je pense que la chaîne a fait quelque chose comme ça

  • allowUmdGlobalAccessFromModules - le plus précis mais tellement long
  • assumeGlobalUmd - pouah
  • allowModuleUmdGlobals - "globaux" ??
  • umdAlwaysGlobal - 🤢
  • allowUmdGlobals - mais je peux déjà?
  • allowUmdGlobalAccess - ignore la partie module mais personne ne s'en soucie probablement?

Je choisirais le dernier si je suis obligé de

Je vous remercie!

J'aime bien allowUmdGlobalAccessFromModules car, bien qu'il soit long, sa précision le rend plus facile à retenir. Je pense: "Quelle est cette option qui permet d'accéder aux globaux UMD à partir de modules? Oh oui, c'est allowUmdGlobalAccessFromModules , bien sûr!"

L'utilisation du préfixe "allow" correspond à la convention de dénomination des autres options, ce qui est bien.

De plus ... il y a d'autres options qui sont à peu près aussi longues :)

allowUmdGlobalAccessFromModules : 31 caractères

allowSyntheticDefaultImports : 28 caractères
strictPropertyInitialization : 28 caractères
suppressExcessPropertyErrors : 28 caractères
suppressImplicitAnyIndexErrors : 30 caractères
forceConsistentCasingInFileNames : 32 caractères

Quelle est la solution de contournement actuelle? Je recherche sur Google depuis une heure et je ne trouve aucune solution viable.
Je préfère ne pas convertir en `` tout '' ou revenir à une version de travail de Typescript, mais je ne trouve aucune autre option.
Y a-t-il une version expérimentale quelque part qui a un indicateur de compilateur qui résout ce problème?
(au fait, 'allowUmdGlobalAccessFromModules' est un excellent nom; ce n'est pas comme si nous le tapions 50 fois par jour :-))

Nous utilisons tsc 3.2.2 avec lodash inclus statiquement dans le fichier HTML supérieur; avec require.js; d.ts obtenu à partir du dernier DefinitelyTyped; exemple de code dont la compilation échoue:

/// <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;

(s'il vous plaît ne me dites pas que je dois renverser le projet, je sais que nous sommes en retard sur certains aspects)

Mettre à jour: ((window) ._) / * FIXME https://github.com/Microsoft/TypeScript/issues/10178 * /. sortBy (...) fonctionne mais cher Seigneur, c'est moche :-P

@Gilead , la solution de ce commentaire fonctionne très bien pour le moment: https://github.com/Microsoft/TypeScript/issues/10178#issuecomment -263030856

Y a-t-il des progrès à ce sujet? J'ai un cas où la solution de contournement mentionnée ne semble pas fonctionner (en utilisant [email protected] ) parce que je rencontre ce problème.


J'ai d'abord essayé ceci:

import 'firebase';

declare global {
  const firebase;
}

Cela donne implicitement au global firebase le type any , puis lui applique l'espace de noms (avec le même nom). Tout d'abord, cela a semblé fonctionner car il affiche les info-bulles / intellisense appropriées pour toutes les clés de niveau supérieur de firebase .

Cependant, cela ne fonctionne pas réellement (je suppose car il passe ensuite à l'utiliser comme type any , ce qui pourrait être un bogue?):


J'ai donc essayé la solution de contournement mentionnée ici sans succès (cela fonctionne pour d'autres cependant):

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

declare global {
  const firebase: typeof _firebase;
}

=> 'firebase' est référencé directement ou indirectement dans sa propre annotation de type.
(même si l'espace de noms est aliasé?)


J'ai aussi essayé

import * as _firebase from 'firebase';

declare global {
  const firebase: typeof _firebase;
}

=> Définition circulaire de l'alias d'importation '_firebase'.
(peut-être à cause de export = firebase; export as namespace firebase; dans sa définition ?)


Et enfin, si je fais juste le import 'firebase' , je suis de retour

«firebase» fait référence à un global UMD, mais le fichier actuel est un module. [2686]


Si quelqu'un a une solution pour cela, ce serait très apprécié. Sinon, toutes les suggestions pour résoudre ce problème qui ont été mentionnées jusqu'à présent me semblent vraiment bien (indicateur, référence à triple barre oblique, types dans tsconfig, ayant un objet global ou external dans tsconfig).

Commentaire de Re

Cela ne peut pas laisser tout cela être dans la veine et revenir aux globaux!

Je n'essaye pas de revenir aux globaux, j'essaie juste de charger quelques dépendances lourdes séparément de mon bundle d'applications, tout en utilisant des modules pour tout le reste, car cela apporte quelques avantages: les dépendances peuvent être mises en cache correctement parce qu'ils ne sont pas mis à jour aussi souvent que mon ensemble d'applications; la taille de mon bundle n'explose pas (parfois à cause de la division du code, le bundler inclut la même dépendance plusieurs fois), ce qui signifie moins de téléchargement pour les utilisateurs de mon application; reconstruire mes bundles pendant le développement est bien plus rapide.

C'est vraiment une fonctionnalité très facile à ajouter; ce serait formidable pour un membre de la communauté de le faire.

@RyanCavanaugh J'ai examiné la compiler/types.ts et modifier le chèque global umd dans compiler/checker.ts , et je pense que je dois l'ajouter à compiler/commandLineParser.ts aussi ... mais je pense que cela me prendrait un certain temps pour le faire car je ne connais pas du tout la source (comme comment ajouter une description pour le drapeau CLI sans casser le i18n) . Pour l'instant, je vais attendre que quelqu'un d'autre qui connait déjà la source s'en charge.

@simonhaenisch Vous pouvez le déclarer dans un fichier de déclaration non-module, et pour éviter toute référence circulaire, vous pouvez le réexporter dans une autre déclaration de module UMD. L'original firebase est déclaré comme un espace de noms, heureusement pour nous, il augmentera notre déclaration, ne causant pas d'erreur.

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

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

Malheureusement, ce que nous avons déclaré est une valeur, pas un espace de noms, donc vous ne pouvez pas faire quelque chose comme let x: firebase.SomeInterface , le seul moyen d'aliaser un espace de noms est de déclarer une importation, mais vous ne pouvez pas declare import firebase = UMD.firebase; , car l'espace de noms ne l'augmentera pas. Bien sûr, nous pouvons utiliser un nom différent uniquement pour namspace en utilisant in type, mais cela causera de la confusion, je préfère supprimer le reste du code dont j'ai parlé ci-dessus, l'assigner à une valeur globale au moment de l'exécution, faire fonctionner l'alias d'importation vraiment.

Semblable au commentaire précédent, nous chargeons paresseusement hls.js (UMD) et les types de référence ainsi:

En hls.d.ts :

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

Dans le fichier .ts en utilisant le module UMD à chargement différé:

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

Testé dans Typescript> = 3.0.1 et 3.4.1.

La justification est la prise en charge incomplète du navigateur pour les importations de modules dynamiques.

@MatthiasHild Peut-il être fait sans le commentaire /// <reference path="hls.d.ts" /> ?

EDIT, oui c'est possible, tant que la déclaration est dans un fichier .d.ts inclus qui n'a PAS le même nom qu'un autre fichier .ts , basé sur cette question SO (c'est ce qui m'a et pourquoi j'ai demandé).

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

blakeembrey picture blakeembrey  ·  171Commentaires

xealot picture xealot  ·  150Commentaires

OliverJAsh picture OliverJAsh  ·  242Commentaires

chanon picture chanon  ·  138Commentaires

kimamula picture kimamula  ·  147Commentaires