Module d'importation Typescript es6 "Le fichier n'est pas une erreur de module"

127

J'utilise typescript 1.6 avec la syntaxe des modules es6.

Mes fichiers sont:

test.ts:

module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
}

main.ts:

import App from './test';

var a = new App.SomeClass();

Lorsque j'essaie de compiler le main.tsfichier, j'obtiens cette erreur:

Erreur TS2306: le fichier 'test.ts' n'est pas un module.

Comment puis-je y parvenir?

Bazinga
la source
J'ai eu ce problème, je n'avais pas de constructeur dans la classe, j'en ai ajouté un et le problème a disparu
dorriz

Réponses:

139

Extended - pour fournir plus de détails en fonction de certains commentaires

L'erreur

Erreur TS2306: le fichier 'test.ts' n'est pas un module.

Provient du fait décrit ici http://exploringjs.com/es6/ch_modules.html

17. Modules

Ce chapitre explique le fonctionnement des modules intégrés dans ECMAScript 6.

17.1 Aperçu

Dans ECMAScript 6, les modules sont stockés dans des fichiers. Il y a exactement un module par fichier et un fichier par module. Vous avez deux façons d'exporter des choses à partir d'un module. Ces deux méthodes peuvent être mélangées, mais il est généralement préférable de les utiliser séparément.

17.1.1 Exportations nommées multiples

Il peut y avoir plusieurs exportations nommées:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
...

17.1.2 Exportation par défaut unique

Il peut y avoir une seule exportation par défaut. Par exemple, une fonction:

//------ myFunc.js ------
export default function () { ··· } // no semicolon!

Sur la base de ce qui précède, nous avons besoin du export, dans le cadre du fichier test.js. Ajustez-en le contenu comme ceci:

// test.js - exporting es6
export module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
  export class OtherClass {
    getName(): string {
      return 'name';
    }
  }
}

Et maintenant, nous pouvons l'importer de trois manières:

import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";

Et nous pouvons consommer des trucs importés comme ceci:

var a1: app1.App.SomeClass  = new app1.App.SomeClass();
var a2: app1.App.OtherClass = new app1.App.OtherClass();

var b1: app2.App.SomeClass  = new app2.App.SomeClass();
var b2: app2.App.OtherClass = new app2.App.OtherClass();

var c1: App.SomeClass  = new App.SomeClass();
var c2: App.OtherClass = new App.OtherClass();

et appelez la méthode pour la voir en action:

console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())

La partie d'origine essaie de réduire la complexité de l'utilisation de l'espace de noms

Pièce d'origine:

Je suggérerais vraiment fortement de vérifier ces questions et réponses:

Comment utiliser les espaces de noms avec les modules externes TypeScript?

Permettez-moi de citer la première phrase:

N'utilisez pas d '"espaces de noms" dans les modules externes.

Ne fais pas ça.

Sérieusement. Arrêtez.

...

Dans ce cas, nous n'avons tout simplement pas besoin de l' moduleintérieur de test.ts. Cela pourrait être le contenu de celui-ci ajusté test.ts:

export class SomeClass
{
    getName(): string
    {
        return 'name';
    }
}

En savoir plus ici

Exporter =

Dans l'exemple précédent, lorsque nous avons consommé chaque validateur, chaque module n'a exporté qu'une seule valeur. Dans de tels cas, il est fastidieux de travailler avec ces symboles via leur nom qualifié alors qu'un seul identifiant ferait tout aussi bien l'affaire.

La export =syntaxe spécifie un seul objet qui est exporté à partir du module . Cela peut être une classe, une interface, un module, une fonction ou une énumération. Lors de l'importation, le symbole exporté est consommé directement et n'est qualifié par aucun nom.

nous pouvons le consommer plus tard comme ceci:

import App = require('./test');

var sc: App.SomeClass = new App.SomeClass();

sc.getName();

En savoir plus ici:

Chargement de module en option et autres scénarios de chargement avancés

Dans certains cas, vous souhaiterez peut-être charger un module uniquement sous certaines conditions. Dans TypeScript, nous pouvons utiliser le modèle illustré ci-dessous pour implémenter cela et d'autres scénarios de chargement avancés pour appeler directement les chargeurs de module sans perdre la sécurité de type.

Le compilateur détecte si chaque module est utilisé dans le JavaScript émis. Pour les modules qui ne sont utilisés que dans le cadre du système de types, aucun appel obligatoire n'est émis. Cette élimination des références inutilisées est une bonne optimisation des performances et permet également le chargement facultatif de ces modules.

L'idée centrale du modèle est que l'instruction import id = require ('...') nous donne accès aux types exposés par le module externe. Le chargeur de module est appelé (via require) dynamiquement, comme indiqué dans les blocs if ci-dessous. Cela exploite l'optimisation de la sélection des références afin que le module ne soit chargé qu'en cas de besoin. Pour que ce modèle fonctionne, il est important que le symbole défini via l'importation ne soit utilisé que dans les positions de type (c'est-à-dire jamais dans une position qui serait émise dans le JavaScript).

Radim Köhler
la source
1
Mais ceci: import App = require ('./ test'); n'est pas la syntaxe des modules es6. c'est js commun. Puis-je le faire avec la syntaxe des modules ES6?
Bazinga le
@JsIsAwesome Vous essayez de mélanger des modules JS avec des modules Typescript. Vous devez utiliser l'un ou l'autre, pas un mélange des deux.
JJJ
Cette réponse ne fait pas référence à la syntaxe
ES6
@phiresky, que voulez-vous dire?
Radim Köhler
1
Merci, c'est super.
phiresky
24

Les réponses ci-dessus sont correctes. Mais juste au cas où ... Vous avez la même erreur dans VS Code. J'ai dû ré-enregistrer / recompiler le fichier qui provoquait une erreur.

A. Tim
la source
3
Cela a fonctionné pour moi. J'ai simplement supprimé un point-virgule, l'ai rajouté et enregistré à nouveau le fichier, puis l'exécution de Webpack a fonctionné. Super moment pour être en vie.
Ray Hogan le
1
Je suis habitué à Webstorm et je n'ai pas réalisé que les fichiers ne sont pas enregistrés automatiquement dans VS Code. Cette réponse m'a sauvé beaucoup de douleur, merci.
cib
Il existe un paramètre pour l'enregistrement automatique dans VS Code. Je ne l'utilise pas car VS Code sauvegarde déjà les fichiers non enregistrés et je n'utilise pas toujours git.
aamarks le
13

Comment puis-je y parvenir?

Votre exemple déclare un module interne TypeScript <1.5 , qui est maintenant appelé un espace de noms . L'ancienne module App {}syntaxe équivaut désormais à namespace App {}. En conséquence, les travaux suivants:

// test.ts
export namespace App {
    export class SomeClass {
        getName(): string {
            return 'name';
        }
    }
}

// main.ts
import { App } from './test';
var a = new App.SomeClass();

Cela étant dit...

Essayez d'éviter d'exporter des espaces de noms et d'exporter à la place des modules (qui étaient auparavant appelés modules externes ). Si nécessaire, vous pouvez utiliser un espace de noms lors de l'importation avec le modèle d'importation d'espace de noms comme ceci:

// test.ts
export class SomeClass {
    getName(): string {
        return 'name';
    }
}

// main.ts
import * as App from './test'; // namespace import pattern
var a = new App.SomeClass();
Shaun Luttin
la source
1
C'est toujours une bonne pratique? Selon cette réponse ( stackoverflow.com/a/35706271/2021224 ), tenter d'importer une fonction ou une classe comme celle-ci puis l'invoquer - "est illégal selon la spécification ES6".
Andrey Prokhorov
2

En plus de la réponse de A. Tim, il y a des moments où même cela ne fonctionne pas, vous devez donc:

  1. Réécrivez la chaîne d'importation en utilisant l'intellisense. Parfois, cela résout le problème
  2. Redémarrez VS Code
ZenVentzi
la source
1
idem pour stackblitz - fichier recompilé qui importe le module et tout fonctionne bien,
bravo
J'ai également vécu cela lorsque mon code n'était pas correctement formaté. VSCode a indenté mon code de classe copier-coller lorsque je divisais mes classes en leurs propres fichiers, et VSCode a tout mis en retrait après le export class... {, ce que angular n'aimait pas, ce qui m'a posé ce problème. Après avoir corrigé le formatage, compilé sans problème.
Guy Park
0

En plus de la réponse de Tim, ce problème est survenu pour moi lorsque je divisais un refactoring d'un fichier, le divisant en leurs propres fichiers.

VSCode, pour une raison quelconque, a indenté des parties de mon code [class], ce qui a causé ce problème. C'était difficile à remarquer au début, mais après avoir réalisé que le code était en retrait, j'ai formaté le code et le problème a disparu.

par exemple, tout ce qui se trouvait après la première ligne de la définition de classe était automatiquement mis en retrait pendant le collage.

export class MyClass extends Something<string> {
    public blah: string = null;

    constructor() { ... }
  }
Guy Park
la source