Módulo de importação do typescript es6 "O arquivo não é um erro do módulo"

127

Estou usando o typescript 1.6 com sintaxe de módulos es6.

Meus arquivos são:

test.ts:

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

main.ts:

import App from './test';

var a = new App.SomeClass();

Quando estou tentando compilar o main.tsarquivo, recebo este erro:

Erro TS2306: O arquivo 'test.ts' não é um módulo.

Como posso conseguir isso?

Bazinga
fonte
Eu tive esse problema, eu não tenho um construtor na classe, acrescentou um e problema foi embora
dorriz

Respostas:

139

Estendido - para fornecer mais detalhes com base em alguns comentários

O erro

Erro TS2306: O arquivo 'test.ts' não é um módulo.

Vem do fato descrito aqui http://exploringjs.com/es6/ch_modules.html

17. Módulos

Este capítulo explica como os módulos internos funcionam no ECMAScript 6.

17.1 Visão geral

No ECMAScript 6, os módulos são armazenados em arquivos. Há exatamente um módulo por arquivo e um arquivo por módulo. Você tem duas maneiras de exportar coisas de um módulo. Essas duas maneiras podem ser misturadas, mas geralmente é melhor usá-las separadamente.

17.1.1 Várias exportações nomeadas

Pode haver várias exportações nomeadas:

//------ 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 Exportação padrão única

Pode haver uma única exportação padrão. Por exemplo, uma função:

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

Com base no exposto, precisamos de export, como parte do arquivo test.js. Vamos ajustar o conteúdo assim:

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

E agora podemos importá-lo com estas três maneiras:

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

E podemos consumir coisas 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();

e chame o método para vê-lo em ação:

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

A peça original está tentando ajudar a reduzir a quantidade de complexidade no uso do espaço para nome

Peça original:

Eu realmente sugiro fortemente para verificar este Q & A:

Como uso os espaços para nome com os módulos externos do TypeScript?

Deixe-me citar a primeira frase:

Não use "namespaces" em módulos externos.

Não faça isso.

Seriamente. Pare.

...

Nesse caso, simplesmente não precisamos moduledentro de test.ts. Este poderia ser o conteúdo ajustado test.ts:

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

Leia mais aqui

Exportar =

No exemplo anterior, quando consumimos cada validador, cada módulo exportou apenas um valor. Em casos como esse, é complicado trabalhar com esses símbolos através de seus nomes qualificados, quando um único identificador faria o mesmo.

A export =sintaxe especifica um único objeto que é exportado do módulo . Pode ser uma classe, interface, módulo, função ou enumeração. Quando importado, o símbolo exportado é consumido diretamente e não é qualificado por nenhum nome.

mais tarde podemos consumi-lo assim:

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

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

sc.getName();

Leia mais aqui:

Carregamento opcional do módulo e outros cenários de carregamento avançado

Em alguns casos, você pode querer carregar apenas um módulo sob algumas condições. No TypeScript, podemos usar o padrão mostrado abaixo para implementar este e outros cenários avançados de carregamento para chamar diretamente os carregadores de módulos sem perder a segurança do tipo.

O compilador detecta se cada módulo é usado no JavaScript emitido. Para módulos que são usados ​​apenas como parte do sistema de tipos, nenhuma chamada requerida é emitida. Essa seleção de referências não utilizadas é uma boa otimização de desempenho e também permite o carregamento opcional desses módulos.

A idéia central do padrão é que a instrução import id = require ('...') nos dê acesso aos tipos expostos pelo módulo externo. O carregador do módulo é chamado (através da exigência) dinamicamente, conforme mostrado nos blocos if abaixo. Isso aproveita a otimização da seleção de referência, para que o módulo seja carregado apenas quando necessário. Para que esse padrão funcione, é importante que o símbolo definido por importação seja usado apenas nas posições de tipo (ou seja, nunca em uma posição que seria emitida no JavaScript).

Radim Köhler
fonte
1
Mas isto: import App = require ('./ test'); não é a sintaxe dos módulos es6. isso é js comum. Posso fazer isso com a sintaxe dos módulos es6?
Bazinga
@JsIsAwesome Você está tentando misturar módulos JS com módulos Typescript. Você precisa usar um ou outro, não uma mistura dos dois.
JJJ
Esta resposta não se refere à sintaxe ES6
phiresky
@phiresky, o que você quer dizer?
Radim Köhler 12/12
1
Obrigado, isso é ótimo.
phiresky
24

As respostas acima estão corretas. Mas por via das dúvidas ... Obtive o mesmo erro no VS Code. Teve que salvar novamente / recompilar o arquivo que estava lançando um erro.

A. Tim
fonte
3
Isso funcionou para mim. Simplesmente removi um ponto-e-vírgula, o adicionei novamente e salvei o arquivo novamente e, em seguida, executando o Webpack funcionou. Ótima hora de estar vivo.
Ray Hogan
1
Estou acostumado a Webstorm e não percebi que os arquivos não são salvos automaticamente no VS Code. Essa resposta me salvou muita dor, obrigado.
cib 31/01
Há uma configuração para salvamento automático no VS Code. Não o uso porque o VS Code já faz backup de arquivos não salvos e nem sempre uso o git.
aamarks 15/07/19
13

Como posso conseguir isso?

Seu exemplo declara um módulo interno TypeScript <1.5 , que agora é chamado de espaço para nome . A module App {}sintaxe antiga agora é equivalente a namespace App {}. Como resultado, o seguinte funciona:

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

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

Dito isto ...

Tente evitar a exportação de espaços para nome e, em vez disso, exporte os módulos (que antes eram chamados de módulos externos ). Se necessário, você pode usar um espaço para nome na importação com o padrão de importação do espaço para nome 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
fonte
1
Ainda é uma boa prática? De acordo com esta resposta ( stackoverflow.com/a/35706271/2021224 ), tentar importar uma função ou classe como esta e depois invocá-la - "é ilegal de acordo com as especificações do ES6".
Andrey Prokhorov
2

Além da resposta de A. Tim, há momentos em que mesmo isso não funciona, então você precisa:

  1. Reescreva a cadeia de importação, usando o intellisense. Às vezes isso corrige o problema
  2. Reiniciar o código VS
ZenVentzi
fonte
1
mesmo para stackblitz - arquivo recompilados que as importações do módulo e tudo funciona bem, elogios
godblessstrawberry
Eu também experimentei isso quando meu código não estava formatado corretamente. O VSCode recuou meu código de classe copiar + colar quando dividia minhas classes em seus próprios arquivos, e o VSCode recuou tudo após o export class... {que o angular não gostou, dando-me esse problema. Depois de corrigir a formatação, compilado sem problemas.
Guy Park
0

Além da resposta de Tim, esse problema ocorreu quando eu estava dividindo uma refatoração de um arquivo, dividindo-o em seus próprios arquivos.

O VSCode, por algum motivo, recuou partes do meu código [class], o que causou esse problema. Isso foi difícil de notar no começo, mas depois que percebi que o código estava recuado, formatei o código e o problema desapareceu.

por exemplo, tudo após a primeira linha da definição de classe foi recuado automaticamente durante a colagem.

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

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