Módulo de importación de mecanografiado es6 "El archivo no es un error de módulo"

127

Estoy usando typecript 1.6 con sintaxis de módulos es6.

Mis archivos son:

test.ts:

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

main.ts:

import App from './test';

var a = new App.SomeClass();

Cuando intento compilar el main.tsarchivo, aparece este error:

Error TS2306: el archivo 'test.ts' no es un módulo.

¿Cómo puedo lograr eso?

Bazinga
fuente
Tuve este problema, no tenía un constructor en la clase, agregué uno y el problema desapareció
dorriz

Respuestas:

139

Extendido : para proporcionar más detalles basados ​​en algunos comentarios

El error

Error TS2306: el archivo 'test.ts' no es un módulo.

Proviene del hecho descrito aquí http://exploringjs.com/es6/ch_modules.html

17. módulos

Este capítulo explica cómo funcionan los módulos integrados en ECMAScript 6.

17.1 Descripción general

En ECMAScript 6, los módulos se almacenan en archivos. Hay exactamente un módulo por archivo y un archivo por módulo. Tiene dos formas de exportar cosas desde un módulo. Estas dos formas se pueden mezclar, pero generalmente es mejor usarlas por separado.

17.1.1 Múltiples exportaciones con nombre

Puede haber múltiples exportaciones con nombre:

//------ 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 Exportación predeterminada única

Puede haber una única exportación predeterminada. Por ejemplo, una función:

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

En base a lo anterior, necesitamos el export, como parte del archivo test.js. Vamos a ajustar el contenido de esta manera:

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

Y ahora podemos importarlo de estas tres maneras:

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

Y podemos consumir cosas importadas como esta:

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

y llame al método para verlo en acción:

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 parte original está tratando de ayudar a reducir la cantidad de complejidad en el uso del espacio de nombres

Parte original:

Realmente recomendaría que revise estas preguntas y respuestas:

¿Cómo uso espacios de nombres con módulos externos TypeScript?

Permítanme citar la primera oración:

No utilice "espacios de nombres" en módulos externos.

No hagas esto.

Seriamente. Detener.

...

En este caso, simplemente no necesitamos moduledentro de test.ts. Este podría ser el contenido ajustado test.ts:

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

Leer más aquí

Exportar =

En el ejemplo anterior, cuando consumimos cada validador, cada módulo solo exportaba un valor. En casos como este, es engorroso trabajar con estos símbolos a través de su nombre calificado cuando un solo identificador funcionaría igual de bien.

La export =sintaxis especifica un único objeto que se exporta desde el módulo . Puede ser una clase, interfaz, módulo, función o enumeración. Cuando se importa, el símbolo exportado se consume directamente y no está calificado por ningún nombre.

luego podemos consumirlo así:

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

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

sc.getName();

Leer más aquí:

Módulo opcional de carga y otros escenarios de carga avanzada

En algunos casos, es posible que desee cargar solo un módulo bajo ciertas condiciones. En TypeScript, podemos usar el patrón que se muestra a continuación para implementar este y otros escenarios de carga avanzados para invocar directamente a los cargadores de módulos sin perder la seguridad de los tipos.

El compilador detecta si cada módulo se usa en el JavaScript emitido. Para los módulos que solo se usan como parte del sistema de tipos, no se emiten llamadas obligatorias. Esta selección de referencias no utilizadas es una buena optimización del rendimiento y también permite la carga opcional de esos módulos.

La idea central del patrón es que la instrucción import id = require ('...') nos da acceso a los tipos expuestos por el módulo externo. El cargador de módulos se invoca (a través de require) dinámicamente, como se muestra en los bloques if a continuación. Esto aprovecha la optimización de selección de referencias para que el módulo solo se cargue cuando sea necesario. Para que este patrón funcione, es importante que el símbolo definido a través de la importación solo se use en posiciones de tipo (es decir, nunca en una posición que se emitiría en JavaScript).

Radim Köhler
fuente
1
Pero esto: import App = require ('./ test'); no es la sintaxis de los módulos es6. esto es común js. ¿Puedo hacerlo con la sintaxis de los módulos es6?
Bazinga
@JsIsAwesome Estás intentando mezclar módulos JS con módulos de tipografía. Necesita usar uno u otro, no una mezcla de ambos.
JJJ
Esta respuesta no se refiere a la sintaxis de ES6
phiresky
@phiresky, ¿qué quieres decir?
Radim Köhler
1
Gracias, eso es genial.
phiresky
24

Las respuestas anteriores son correctas. Pero por si acaso ... Tengo el mismo error en VS Code. Tuve que volver a guardar / recompilar el archivo que arrojaba el error.

A. Tim
fuente
3
Esto funcionó para mí. Simplemente eliminé un punto y coma, lo volví a agregar y guardé el archivo nuevamente, y luego funcionó Webpack. Buen momento para estar vivo.
Ray Hogan
1
Estoy acostumbrado a Webstorm y no me di cuenta de que los archivos no se guardan automáticamente en VS Code. Esta respuesta me ahorró mucho dolor, gracias.
cib
Hay una configuración para guardar automáticamente en VS Code. No lo uso porque VS Code ya realiza copias de seguridad de archivos no guardados y no siempre uso git.
aamarks
13

¿Cómo puedo lograr eso?

Su ejemplo declara un módulo interno TypeScript <1.5 , que ahora se denomina espacio de nombres . La module App {}sintaxis anterior ahora es equivalente a namespace App {}. Como resultado, lo siguiente funciona:

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

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

Habiendo dicho eso...

Intente evitar exportar espacios de nombres y, en su lugar, exporte módulos (que anteriormente se denominaban módulos externos ). Si es necesario, puede usar un espacio de nombres en la importación con el patrón de importación del espacio de nombres como este:

// 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
fuente
1
¿Sigue siendo una buena práctica? Según esta respuesta ( stackoverflow.com/a/35706271/2021224 ), intentar importar una función o clase como esta y luego invocarla: "es ilegal de acuerdo con la especificación ES6".
Andrey Prokhorov
2

Además de la respuesta de A. Tim, hay momentos en que incluso eso no funciona, por lo que debe:

  1. Reescribe la cadena de importación, usando el intellisense. A veces esto soluciona el problema
  2. Reiniciar VS Code
ZenVentzi
fuente
1
lo mismo para stackblitz - archivo compilado que importa el módulo y todo funciona bien, saludos
godblessstrawberry
También experimenté esto cuando mi código no estaba formateado correctamente. VSCode sangró mi código de clase copiar + pegar cuando estaba dividiendo mis clases en sus propios archivos, y VSCode sangró todo después de lo export class... {que angular no le gustó, dándome este problema. Después de arreglar el formato, compilado sin problemas.
Guy Park
0

Además de la respuesta de Tim, este problema se produjo cuando dividí una refactorización de un archivo, dividiéndolo en sus propios archivos.

VSCode, por alguna razón, partes sangradas de mi código [clase], lo que causó este problema. Al principio fue difícil de notar, pero después de darme cuenta de que el código estaba sangrado, lo formateé y el problema desapareció.

por ejemplo, todo después de la primera línea de la definición de Clase se sangraba automáticamente durante el pegado.

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

    constructor() { ... }
  }
Guy Park
fuente