Typescript: Forneça uma maneira de adicionar a extensão de arquivo '.js' ao final dos especificadores do módulo

Criado em 16 jun. 2017  ·  273Comentários  ·  Fonte: microsoft/TypeScript

Para usar os módulos es6 no navegador, você precisa de uma extensão de arquivo .js. No entanto, a saída não o adiciona.

Em ts:
import { ModalBackground } from './ModalBackground';
Na saída ES2015:
import { ModalBackground } from './ModalBackground';

Idealmente, eu gostaria que isso fosse produzido
import { ModalBackground } from './ModalBackground.js';

Dessa forma, posso usar a saída no Chrome 51

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Webpack boilerplate</title>
  <script type="module" src="index.js"></script>
</head>
<body></body>
</html>

image

Relacionado a https://github.com/Microsoft/TypeScript/issues/13422

ES Modules Needs Proposal Suggestion

Comentários muito úteis

Além disso, para generalizar um pouco esse problema, não acho que se trata de adicionar uma extensão .js , mas resolver o especificador do módulo para um caminho real, seja qual for a extensão.

Todos 273 comentários

Não está apenas relacionado ao #13422, é o mesmo problema. Mas as respostas foram bastante negativas, apesar de eu achar que é uma questão importante, então espero que sua questão seja melhor recebida.

Bem, espero que tenha sido adicionado, estávamos realmente ansiosos para discutir meu POC usando isso no meu próximo podcast do TypeScript, mas parece que teremos que esperar para usar o TypeScript sem ferramentas de compilação.

No momento, o TypeScript não reescreve caminhos. É definitivamente irritante, mas atualmente você pode adicionar a extensão .js você mesmo.

@justinfagnani @rictic

Obrigado pela dica, vou escrever um script shell/node para fazer isso.

@DanielRosenwasser faria sentido coletar os problemas do módulo ES6 nativo sob um rótulo?

Além disso, para generalizar um pouco esse problema, não acho que se trata de adicionar uma extensão .js , mas resolver o especificador do módulo para um caminho real, seja qual for a extensão.

Eu me deparei com outro problema que não é realmente o domínio do texto datilografado, mas é para o meu caso de uso.

Não tenho certeza de como lidar com node_modules. Normalmente, o webpack os agrupa no código por meio do ts-loader, mas, obviamente, isso não é entendido pelo navegador:

import { KeyCodes } from 'vanilla-typescript;
https://github.com/quantumjs/vanilla-typescript/blob/master/events/KeyCodes.ts#L3

Adicionar uma extensão js aqui não faz sentido.

Eu acho que teria que haver uma expansão de caminho por typescript ou um resolvedor de URL em execução no servidor.

Eu aprecio que seja um caso de nicho, mas acho que seria uma maneira pela qual a TS poderia brilhar cedo nessa área. Talvez possa ser um plugin para o compilador tsc?

Para quem está chegando a isso e quer uma solução provisória, escrevi um script para adicionar uma extensão de arquivo js para importar instruções:

"use strict";

const FileHound = require('filehound');
const fs = require('fs');
const path = require('path');

const files = FileHound.create()
  .paths(__dirname + '/browserLoading')
  .discard('node_modules')
  .ext('js')
  .find();


files.then((filePaths) => {

  filePaths.forEach((filepath) => {
    fs.readFile(filepath, 'utf8', (err, data) => {


      if (!data.match(/import .* from/g)) {
        return
      }
      let newData = data.replace(/(import .* from\s+['"])(.*)(?=['"])/g, '$1$2.js')
      if (err) throw err;

      console.log(`writing to ${filepath}`)
      fs.writeFile(filepath, newData, function (err) {
        if (err) {
          throw err;
        }
        console.log('complete');
      });
    })

  })
});

Eu poderia fazer isso em uma ferramenta cli ..

O comentário de @justinfagnani acerta em cheio.

Além disso, para generalizar um pouco esse problema, não acho que se trata de adicionar uma extensão .js, mas resolver o especificador do módulo para um caminho real, qualquer que seja a extensão.

quando você escreve

import { KeyCodes } from 'vanilla-typescript';

ou para esse assunto

import { KeyCodes } from 'vanilla-javascript';

você está importando de um especificador de módulo, pode ou não ser um arquivo, mas adicionar .js ao final neste caso provavelmente não resultará em uma resolução válida.

Se você estiver escrevendo um aplicativo NodeJS, o algoritmo NodeJS Require tentará várias resoluções, mas provavelmente _não_ tentará resolvê-lo para 'vanilla-typescript.js' porque ele faz referência a um nome abstrato e, por convenção e configuração, será resolvido ( talvez ao longo de várias tentativas) para algo como '../../../node_modules/vanilla_typescript/index.js' .

Outros ambientes, como o AMD, têm diferenças na forma como executam essa resolução, mas uma coisa que todos esses ambientes têm em comum é a noção de um especificador de módulo abstrato.

Eu trago isso porque as implementações do Módulo ES enviadas em vários navegadores implementam algo que está incompleto. Se considerarmos até mesmo nossas dependências mais simples, e assim que abordarmos o assunto das transitivas, fica claro que será necessário haver uma maneira de configurar a coisa doggone.

Isso pode estar longe, mas como você está descobrindo, não é realista escrever para esta (educadamente) prova de implementação de conceito que nos foi dada.

Além disso, não vejo como o TypeScript poderia ajudar aqui, pois o problema é específico do ambiente.

@QuantumInformation seu programa para adicionar .js aos caminhos parece bom, leve, elegante até, mas você está implementando seu próprio empacotador de módulos. Esse é um trabalho divertido e interessante, mas demonstra as deficiências nas implementações atuais disponíveis nos navegadores. Mesmo se você escrever em JavaScript puro, ainda precisará de algo para compilar e empacotar suas dependências importadas de forma transitiva.

Estou basicamente apenas reclamando do fato de que a implementação dos Módulos ES que foi lançado está tremendamente longe de ser adequada.

Novamente NodeJS, RequireJS AMD, Dojo AMD, Sea Package Manager, CommonJS, Browserify, Webpack, SystemJS, todos têm suas próprias maneiras diferentes de fazer as coisas, mas todos fornecem resolução de nomes abstrata. Eles têm que fornecer porque é _fundamental_.

Obrigado por ler meu desabafo.

Não tenho certeza de qual versão do TS o adicionou, mas importações como ' ./file.js' agora funcionam (mesmo que o arquivo seja realmente file.ts).
O TypeScript resolve o arquivo corretamente e gera a importação .js completa para o destino.
lit-html use-o: https://github.com/PolymerLabs/lit-html/blob/master/src/lib/repeat.ts#L15

É possível desde o TS 2.0. Mas ferramentas como o webpack não o suportam, então no final é inútil.

É inútil se alguém estiver usando o ts-loader nas fontes (o caso de uso mais comum).
Ainda é possível agrupar o destino (geralmente a pasta "dist"), pois o arquivo js real existe lá e pode ser encontrado pelo processo de resolução.

Gostaria de saber se eu poderia implementar uma transformação rápida em ts-loader que retira as extensões .js do código de destino, permitindo que se agrupe diretamente das fontes.

Sinta-se à vontade para fazê-lo, isso seria ótimo. Eu postei o problema nos principais carregadores webpack ts, como ts-loader, alguns meses atrás, e fui muito mal recebido...

Para obter informações, não há problema com o plugin rollup typescript, como prova de que é factível.

Não consigo ver o que isso faz de bom até que as implementações do carregador do navegador e a especificação do carregador WGATWG suportem pelo menos _alguma_ configuração porque a maioria das dependências não será carregada corretamente.

Do meu ponto de vista, nada disso importa até que seja prático usar o carregador nativo em uma importação que se refira a um especificador literal de string arbitrário, algo que ainda pode não ser uma URL, e passar por uma transformação que produz o URL real.

Até lá continuaremos dependentes de ferramentas como SystemJS e Webpack.

Eu criei um pequeno transformador que retira o '.js' das instruções de importação/exportação.
Eu usei guardas do tipo tsutils , então yarn add tsutils --dev . (o pacote geralmente é instalado de qualquer maneira se você tiver tslint em seu projeto, então dependência extra)

https://gist.github.com/AviVahl/40e031bd72c7264890f349020d04130a

Usando isso, pode-se agrupar arquivos ts que contêm importações de arquivos que terminam com .js (usando webpack e ts-loader ), e ainda transpilar fontes para módulos esm que podem carregar em o navegador (usando tsc ).

Provavelmente, há um número limitado de casos de uso em que isso é útil.

EDIT: Atualizei a essência para trabalhar com exportações também. é ingênuo e não otimizado, mas funciona.

Algum movimento nesta questão?

Essa questão de extensão nos leva de volta ao início do TypeScript e por que um tsconfig.json era necessário e por que uma opção module foi adicionada à configuração compilerOptions .

Como essa questão de extension de extensão é importante apenas para o ES2015+, pois o require é capaz de resolver muito bem, deixe-o ser adicionado pelo compilador quando o código de destino for ES2015+.

  1. .js por .ts
  2. .jsx por .tsx

Olá, estou chegando tarde, mas gostaria de ajudar. Estou tendo problemas para entender qual é o problema aqui. A partir do exemplo OP é:

import { ModalBackground } from './ModalBackground';

O problema é que não sabemos o que é './ModalBackground' ? Pode ser uma pasta ou outra coisa?

Se executarmos tsc em todo o projeto e soubermos que ModalBackground.ts existe, saberemos que é seguro adicionar a extensão, não?

Esta questão também é algo que a comunidade RxJS está muito interessada. Qual é o cronograma de uma solução para isso? É mesmo priorizado? Existem transformações de terceiros que ajudariam?

Não tenho certeza se isso é um problema se o destino de saída for ES2015, não é? Isso pode cair no domínio de um recurso de navegador ES2015. Ainda mais, @justinfagnani não podemos pressionar por isso como uma meta de plataforma para se preocupar? (Talvez precise bifurcar em thread separado).

Ainda mais, @justinfagnani não podemos pressionar por isso como uma meta de plataforma para se preocupar? (Talvez precise bifurcar em thread separado).

Sim, é claro que muitas pessoas querem que a plataforma suporte algum tipo de especificador básico, mas o fato atual é que isso não acontece e não há nenhuma proposta para adicioná-los. Precisamos passar por todo esse processo, provavelmente plurianual.

Mesmo se eventualmente obtivermos suporte ao especificador básico, é incrivelmente improvável que seja na forma de resolução de módulo de nó como está. Portanto, haverá uma incompatibilidade entre o algoritmo de resolução usado pelo tsc para encontrar arquivos e o algoritmo de resolução usado pelos navegadores (e possivelmente até o suporte ao módulo nativo do nó, afaik).

Seria ótimo se o tsc pudesse reificar qual caminho ele usou para encontrar outro módulo, para que as ferramentas e ambientes downstream não interpretem especificadores com uma opinião conflitante.

@justinfagnani já são interpretados com opinião conflitante. O TS produz um arquivo JS para o qual o código JS que ele produz não aponta. ES6 é a coisa mais próxima de uma maneira oficialmente correta de fazer JavaScript, então se o código ES6 produzido pelo TypesScript estiver errado, este é um bug puro e simples. Não há necessidade de esperar por nenhuma proposta e tal, apenas corrija o bug do TypeScript. Mas hoje as pessoas sentem que se não encontrarem defeitos em alguma coisa e passarem por 10 camadas de proposta antes de agir, então não estão agindo intelectualmente. Me dá um tempo.

@aluanhaddad É verdade que muitos projetos não se beneficiarão, mas existem alguns projetos que não usam dependências npm (ou que são capazes de lidar com as dependências npm de alguma forma), então esses projetos se beneficiariam.

Também é muito útil para bibliotecas TypeScript, que são compiladas para ES6. No momento, essas bibliotecas não podem ser usadas nativamente no navegador, mas se o TypeScript gerasse uma extensão .js , elas funcionariam.

@justinfagnani Ainda não está padronizado ou implementado, mas existe uma proposta para fazer os pacotes npm funcionarem no navegador.

O mapa de nomes de pacotes pode ser gerado automaticamente pelo compilador TypeScript ou por outra ferramenta.

Então, estou analisando isso novamente, houve alguma solução legal para isso, além do meu script de nó?

Eu tenho usado esta solução:
https://github.com/Microsoft/TypeScript/issues/16577#issuecomment -343610106

Mas acredito que se o módulo não tiver a extensão do arquivo, mas for servido com o tipo MIME correto, isso deve resolver.

Algum movimento sobre isso?

@Kingwl Você suportará algumas outras extensões de arquivo? como .mjs .es .esm .

talvez não, esta é outra característica

Como isso é mesmo uma coisa? O compilador typescript _sabe_ que a saída de destino é um arquivo JS. Estou navegando nesses tópicos há 15 minutos e ainda não entendo por que ele omite a extensão.

Pelo número de referências a esse problema, presumo que ele esteja se movendo na direção certa. Vou fazer outra tentativa em breve.

Como isso é mesmo uma coisa? O compilador typescript _sabe_ que a saída de destino é um arquivo JS. Estou navegando nesses tópicos há 15 minutos e ainda não entendo por que ele omite a extensão.

Existem casos de uso comuns, que as pessoas usam, onde a falta de extensão permite uma infraestrutura mais flexível. O node requer hook e o webpack loader são dois desses casos.

Como isso é mesmo uma coisa? O compilador typescript _sabe_ que a saída de destino é um arquivo JS. Estou navegando nesses tópicos há 15 minutos e ainda não entendo por que ele omite a extensão.

Existem casos de uso comuns, que as pessoas usam, onde a falta de extensão permite uma infraestrutura mais flexível. O node requer hook e o webpack loader são dois desses casos.

Nenhum dos quais os módulos do navegador se preocupam.

Seria apenas matar a equipe do typescript para adicionar um sinalizador opt-in para emitir uma extensão .js? Nós _sabemos_ o que estamos fazendo aqui, ou não haveria uma dúzia de tópicos (abertos e fechados) ainda recebendo respostas e perguntas confusas. Entendemos que não é uma deficiência do TS, mas se o TS está aqui para resolver nossos problemas de JS, adicione esse problema à lista, por favor.

AVISO LEGAL:

Sim, eu entendo que isso pode levar a uma tonelada de pessoas postando problemas aqui que "você abriu o webpack", mas realmente, peitos difíceis para essas pessoas. Deve ser opt-in.

Aliás, vasculhando a fonte do TypeScript, vejo importModuleSpecifierEnding - isso pode ser (ab)usado para fazer com que o emissor use terminações .js ?

Talvez mush esta proposta com o esquema tsconfig? https://github.com/domenic/package-name-maps

Neste ponto, eu ficaria feliz se o TypeScript pudesse reescrever automaticamente as importações usando o paths especificado em tsconfig. Mesmo sem suporte ao navegador, isso provavelmente resolveria a maioria dos pontos problemáticos para mim.

Alguma atualização? Alguma tentativa de resolver este problema? Temos todos os principais navegadores que suportam os módulos es por padrão, o padrão para eles exige que a extensão esteja lá. Eu entendo que podemos adicioná-lo manualmente e o tsc entenderá isso, mas isso não deve ser obrigatório, por que não pode simplesmente funcionar?
Desculpe por reclamar, mas este problema é muito antigo agora e nada foi feito ainda...

Como isso é mesmo uma coisa? O compilador typescript _sabe_ que a saída de destino é um arquivo JS. Estou navegando nesses tópicos há 15 minutos e ainda não entendo por que ele omite a extensão.

Existem casos de uso comuns, que as pessoas usam, onde a falta de extensão permite uma infraestrutura mais flexível. O node requer hook e o webpack loader são dois desses casos.

Então, talvez o compilador Typescript possa aceitar uma opção para adicionar as extensões ou não. Talvez pudesse até aceitar um conjunto de regex para adicionar (ou não) a extensão, como a opção include (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

Sim, já foi proposto pelo menos uma vez antes, por que não levar isso em consideração? O TS já possui alguns recursos experimentais que podem mudar no futuro uma vez implementados no navegador, mas o TS já possui sinalizadores para essas especificações instáveis. Por que não ter apenas um sinalizador experimental addImportsExtensions onde faria apenas o module += '.js' , é isso! Sem lógica funky, sem recursos extras. Pode ser um destino diferente se você preferir mantê-lo como um destino separado. Mais do que isso, se você aceitar qualquer um dos itens acima, eu pessoalmente vou cavar o código tsc e fazer um PR para isso, só não quero perder meu tempo se não for aceito de qualquer maneira.

Você pode simplesmente usar uma transformação personalizada para reescrever importações no código emitido (adicionando '.js' ou usando o caminho resolvido de importações de módulo).

Como escrever uma transformação TypeScript
ttypescript: wrapper para tsc que aplica transformações durante a compilação

Talvez já exista uma transformação existente que faça o que você precisa.

Eu sei que isso é possível, eu brinquei bastante com a API do compilador (embora não tanto quanto eu gostaria). O problema é que ele adiciona ferramentas adicionais ao projeto e ferramentas adicionais têm mantenedores adicionais que podem ou não responder a problemas com rapidez suficiente (muitas vezes não por culpa deles, todos nós temos vidas e trabalho). Projetos pequenos são frequentemente abandonados e fazer tudo sozinhos apenas transfere a responsabilidade para nós, então, em vez de cuidar do código de negócios, gastamos tempo com as ferramentas.
Levando em consideração o que foi dito acima, muitos projetos nem consideram isso como uma solução e, em vez disso, adicionam etapas de compilação adicionais, como rollup etc., o que adiciona sobrecarga de configuração adicional e nos leva de volta ao custo adicional de manutenção.
Resumindo: prefiro gastar meu tempo em um PR para o TS oficial, onde tanto eu quanto a comunidade se beneficiariam dele, do que gastá-lo em uma solução personalizada que eu poderia eventualmente abandonar (por não ter tempo ou muitos outros motivos ), ou que não poderia ser usado por mais ninguém no mundo.

@ajafff ​​Poderia ser uma solução, mas acho que o principal problema é o seguinte: o transpilador Typescript gera código fonte errado nos navegadores. É bom ter transformações, mas vejo isso como uma solução alternativa. Gostaria de saber se tenho que me preocupar com detalhes de transpilação e preciso implementar minha própria transformação ou é algo que deve ser gerenciado pelo compilador.

As transformações são uma ferramenta muito poderosa, poderíamos escrever um transpiler inteiro como uma transformação, mas acho que esse não é o caminho certo.

Sim, já foi proposto pelo menos uma vez antes, por que não levar isso em consideração? TS já tem poucos recursos experimentais

O TypeScript tem exatamente um sinalizador experimental que foi adicionado há 3 anos e foi para uma proposta ECMAScript que não é mais compatível com a proposta atual.

o transpilador Typescript gera código fonte errado nos navegadores

Eu entendo suas expectativas, mas como o compilador não reescreve os caminhos que você escreveu, estou surpreso que você não considere as importações do seu próprio código "erradas". 😉

Desculpe @DanielRosenwasser , você já ouviu falar de uma coisa chamada npm? As pessoas postam seus pacotes lá para que todos possamos usá-los. Eu entendo que você possa pensar muito bem de mim, mas infelizmente não sou um autor da grande maioria deles, então não posso editá-los adicionando as extensões.
Se meus projetos usassem apenas meu código, eu ficaria mais agradecido pelo que o typescript traz, pois é realmente minha mão direita na codificação (além do WebStorm). No entanto, estou usando pacotes de terceiros como acho que a maioria de nós e esses não necessariamente contêm as extensões. Alguns projetos, como o rxjs, literalmente esperam que o typescript forneça a maneira de adicionar extensões, caso contrário, seria necessário alterar todo o processo de construção, então voltamos a gastar mais tempo em ferramentas em vez de produto.
Agora, por favor, você poderia responder apenas 3 perguntas?

  1. A equipe datilografada está disposta a enviar esse recurso?
  2. Se sim, você aceitaria um PR?
  3. Se não, quando você planeja lançar isso?

Se a resposta para a 1ª pergunta for 'não', por favor, encerre esta questão declarando oficialmente que você NÃO está disposto a enviar este recurso, não faça os outros esperarem se ele não estiver por vir.

Sim, já foi proposto pelo menos uma vez antes, por que não levar isso em consideração? TS já tem poucos recursos experimentais

O TypeScript tem exatamente um sinalizador experimental que foi adicionado há 3 anos e foi para uma proposta ECMAScript que não é mais compatível com a proposta atual.

o transpilador Typescript gera código fonte errado nos navegadores

Eu entendo suas expectativas, mas como o compilador não reescreve os caminhos que você escreveu, estou surpreso que você não considere as importações do seu próprio código "erradas". 😉

É um bom ponto @DanielRosenwasser , acabei de considerar meu próprio código correto porque parece estar certo lendo a especificação do Typescript (https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#11.3).

Tenho certeza que você leu as especificações do ECMAScript. Na especificação não é determinado se um módulo deve terminar com uma extensão ou não. Nas especificações, a importação de módulos é resolvida usando o algoritmo HostResolveImportedModule, mas a definição é ambígua. O problema não é a especificação ECMAScript. O problema é que os navegadores resolvem os módulos como se o [ModuleRequest], conforme definido nas especificações, fosse um caminho para os recursos.

Tendo isso em mente, basta acessar a página inicial do idioma: https://www.typescriptlang.org/ .

No rodapé da página você pode ler as seguintes linhas:

Começa e termina com JavaScript

O TypeScript começa com a mesma sintaxe e semântica que milhões de desenvolvedores JavaScript conhecem hoje. Use o código JavaScript existente, incorpore bibliotecas JavaScript populares e chame o código TypeScript do JavaScript.

O TypeScript compila para um código JavaScript limpo e simples que é executado em qualquer navegador , no Node.js ou em qualquer mecanismo JavaScript que suporte ECMAScript 3 (ou mais recente).


Você promete um código que roda em todos os navegadores, mas não parece ser verdade, por isso esse problema permanece por mais de um ano.

Como aponta @Draccoz , queremos apenas saber o que você está fazendo com esse problema. Mas é um pouco frustrante ler uma coisa em sua página inicial e o contrário nesta edição.

Não, não estamos dispostos a enviar nada relacionado a isso até que haja pelo menos clareza sobre coisas como interoperabilidade ES no Node e uma estratégia razoável para enviar dependências transitivas que você usaria do npm em primeiro lugar. Se você não estivesse usando o TypeScript, teria o mesmo problema em relação ao gerenciamento e resolução de dependências, portanto, não faz sentido criarmos algo que o ecossistema JS em geral possa desenvolver de forma independente. Mas mesmo que esses problemas fossem resolvidos, não posso garantir que faremos qualquer alteração aqui.

Você promete um código que roda em todos os navegadores, mas não parece ser verdade, por isso esse problema permanece por mais de um ano.

Acho essa interpretação muito literal. var fs = require('fs') não funciona quando você o executa no navegador, HTMLDivElement não está definido no Node e String.prototype.startsWith não funciona em navegadores mais antigos. Para resolver isso, as pessoas criaram ferramentas e bibliotecas/polyfills fora do TypeScript porque se aplicam ao ecossistema JavaScript mais amplo.

Então você pode por favor fechar este assunto? Este é um bloqueador para outros projetos que esperam que o TS o faça ou declare que você não o está fazendo. Se você não pode simplesmente adicionar um sinalizador simples, encerre este problema e informe outras pessoas sobre suas decisões.

@DanielRosenwasser Obrigado por sua resposta rápida, eu realmente aprecio isso. Acho uma escolha sábia.

Acho essa interpretação muito literal. var fs = require('fs') não funciona quando você o executa no navegador, HTMLDivElement não está definido no Node e String.prototype.startsWith não funciona em navegadores mais antigos. Para resolver isso, as pessoas criaram ferramentas e bibliotecas/polyfills fora do TypeScript porque se aplicam ao ecossistema JavaScript mais amplo.

Claro que é, mas o que mais poderia pensar alguém que não sabe nada de Typescript? O fato de minha interpretação ser muito literal é tão verdadeiro quanto o fato de que esse texto pode “confundir” qualquer um que não saiba nada sobre Typescript 😉.

Talvez você possa atualizar seus documentos (https://www.typescriptlang.org/docs/handbook/modules.html) para refletir o comportamento real.

@DanielRosenwasser obrigado novamente por sua resposta. Estou esperando por algo semelhante há um ano.

A razão pela qual eu queria esse recurso era para que eu pudesse ver que tipo de aplicativo da Web eu poderia criar sem nenhuma ferramenta de compilação. Até então eu posso usar aquele script que escrevi anteriormente.

Para pessoas como eu procurando uma solução para poder usar módulos ES e TypeScript no navegador hoje, encontrei https://github.com/guybedford/es-module-shims. Ele atua como uma espécie de polyfill para mapas de nomes de pacotes enquanto aguardamos a finalização das especificações e a implementação do navegador. Ele resolve o problema do @QuantumInformation de não querer usar nenhuma ferramenta de compilação (meu problema também) ao criar um aplicativo da Web simples no TypeScript (além do compilador TS).

import 'knockout'

export class MyViewModel {
    greeting: KnockoutObservable<string>
    target: KnockoutObservable<string>
    constructor() {
        this.greeting = ko.observable('hello')
        this.target = ko.observable('world')
    }
}
<!DOCTYPE html>


md5-f28d4b503a1603c40bfeb342f341bfbe


<main>
    <span data-bind='text: `${greeting()} ${target()}`'></span>
    <script type='module-shim'>
        import 'knockout'
        import { MyViewModel } from 'index'
        ko.applyBindings(new MyViewModel())
    </script>
</main>

Em teoria, uma vez que os mapas de nomes de pacotes são suportados pelos navegadores, você pode simplesmente encontrar/substituir type='module-shim' por type='module' em seus arquivos HTML e alterar o script packagemap para o que for finalizado para inclusão do packagemap no especificação

Provavelmente também vale a pena notar que a extensão .js não é obrigatória por navegadores ou qualquer coisa - você sempre pode configurar seu servidor web para ser mais parecido com unpkg e servir arquivos .js de URLs de solicitação sem extensão. É tudo configurável no lado do servidor web.

@weswigham isso pode ser muito problemático, porque tsc (e resolução de módulo de nó clássico) saberá que ./foo e ./foo.js se referem ao mesmo arquivo, mas os navegadores os tratarão de maneira diferente, mesmo que o redirecionamentos do servidor web. Você precisa ter certeza de que se refere a um arquivo exatamente da mesma maneira em cada importação.

A propósito, esse problema não impede que os módulos gerados pelo TypeScript sejam usados ​​nos navegadores hoje. Apenas sempre importe arquivos com a extensão .js . tsc faz a coisa certa e resolve os tipos do arquivo .ts , e você obtém compatibilidade com o navegador.

@weswigham Tenha em mente que há situações em que você está servindo arquivos sem ter acesso ao servidor web. GitHub Pages, IPFS, S3, etc. Com o advento dos frameworks de aplicativos de página única, está se tornando cada vez mais comum executar "serverless" (onde serverless aqui significa sem um servidor que você controla/configura servindo seus ativos), então você não pode contar com filtros do lado do servidor para servir apple.js quando uma solicitação é feita para apple .

Você precisa ter certeza de que se refere a um arquivo exatamente da mesma maneira em cada importação.

Sempre pode fazer um ou outro 404 dependendo da sua preferência de autoria. Se você usasse links simbólicos em seu projeto, eles causariam um problema semelhante com o qual você também precisaria escolher como lidar.

Apenas sempre importe arquivos com a extensão .js

Sim, isso também funciona bem.

@QuantumInformation Seu snippet usado aqui é para uso aberto? Posso usar em um projeto? 😃

@distante sim pode usar

FYI se você estiver usando o Jest para testar e mudar para extensões para .js na fonte - ele quebra
mas você pode adicionar o seguinte à sua configuração do jest para corrigir isso

  "jest": {
    ...
    "moduleNameMapper": {
      "(.*)\\.js": "$1"
    }
  }

Olá @MrAntix ,

Acho que jest é a biblioteca que deve se adaptar ao TypeScript, não o contrário.

Eu tenho outro site com o qual não quero usar uma ferramenta de construção. Este é o melhor em que estamos:

https://github.com/microsoft/TypeScript/issues/16577#issuecomment -452312753

Como solução alternativa, você pode fazer assim (mesmo que seja um arquivo ts, não js) 😢

Screenshot 2019-06-05 at 22 47 49

Se alguém quiser experimentar:
https://github.com/QuantumInformation/web-gen-bot

No entanto, não consigo fazer com que a depuração de origem funcione com o tsconfig atual, informarei de volta.

No final, voltei ao webpack, node_modules foi o assassino ao tentar fugir das ferramentas de compilação no navegador.

Não é apenas Jest - se você usar tsc para compilar o TypeScript antes de publicar, qualquer módulo JS que importe o pacote resultante será interrompido devido às diferenças na resolução do módulo.

A discussão aqui parece ter se bifurcado um pouco em duas questões relacionadas, mas em última análise separadas:

  • Typescript deve gerar arquivos que podem ser carregados nativamente em um navegador
  • O Typescript deve resolver o fato de que os caminhos do módulo do nó nem sempre são URLs válidos.

Acho que precisamos nos concentrar na primeira questão, pois a segunda é claramente algo que o texto datilografado não pode resolver por si só.

O primeiro problema, no entanto, é absolutamente algo que o Typescript pode resolver e deve priorizar, pois é um grande bloqueador para a maioria das pessoas que desejam usar o Typescript para criar aplicativos da Web direcionados a navegadores modernos.

Na minha opinião, a questão se resume a isso:

Se a execução de tsc gerar um arquivo com uma extensão .js e outro arquivo que importa o primeiro arquivo .js , não há ambiguidade sobre qual extensão usar, e deve haver uma opção de incluir a extensão.

Para todas as instruções de importação que apontam para arquivos que não sejam os arquivos gerados pelo Typescript, acho que não há problema em deixá-los inalterados (como o Typescript faz hoje).

De acordo com a primeira opção, acho que um argumento de linha de comando seria melhor e estaria desativado por padrão. Digo isso porque, se eu usar o webpack, não quero .js adicionados às importações, pois o webpack cuida do agrupamento de módulos.

De qualquer forma, node_modules foi o assassino que me impediu de usar o hack para aplicativos de navegador de módulo nativo.

Digo isso porque, se eu usar o webpack, não quero .js adicionados às importações, pois o webpack cuida do agrupamento de módulos.

O Webpack lida perfeitamente com a extensão .js , portanto, não há diferença.

Na verdade, às vezes é necessário usar .js com Webpack (nas situações em que existem vários arquivos com o mesmo nome, mas extensões diferentes).

Então, você poderia explicar mais sobre por que você não quer importações de .js com o Webpack?

Quando eu digo I don't want eu quis dizer que não preciso para meus casos de uso.

Não vejo uma razão convincente para que não seja o comportamento padrão (sempre relutante em adicionar outro sinalizador de configuração ...)

Definir as importações para .js faz com que o ts-node pare de funcionar corretamente para o arquivo. Isso ocorre porque o ts-node compila apenas um arquivo de cada vez e se o conteúdo do arquivo emitido terminar com require('./foo.js') , quando o nodejs processar esse arquivo, ele tentará carregar ./foo.js que não existe em qualquer lugar no disco e, portanto, ele falhará. Quando o código requer ( ./foo ) por outro lado, o manipulador do ts-node será chamado e poderá compilar ./foo.ts em JS e retornar isso.

Se o TypeScript emitir extensões .js em todos os casos, o ts-node terá o mesmo problema. No entanto, se houver uma opção para alternar se uma extensão é adicionada automaticamente ou não, o ts-node pode desativar essa opção do compilador, o que permitirá que o sistema atual continue funcionando.

Como o Node.js --experimental-modules requer extensões de arquivo obrigatórias, a API para isso é direta sem precisar de análise de dependência - uma opção como --jsext pode reescrever qualquer extensão .ts para .js Extensão .ts como import 'npmpkg.ts' . Este caso é extremamente raro, mas para lidar com isso de forma abrangente na resolução, a regra pode ser fazer uma exceção para _especificadores simples_ ao longo das linhas de - se o especificador simples (não uma URL ou caminho relativo) for um nome de pacote npm válido ( correspondente /^(@[-_\.a-zA-Z\d]+\/)?[-_\.a-zA-Z\d]+$/ , de https://github.com/npm/validate-npm-package-name ), então ignore as extensões .ts na reescrita.

Eu criei um transformador de compilador TypeScript que anexará uma extensão de arquivo .js em qualquer caminho de importação relativo. Isso significa que se o seu arquivo .ts tiver import { Foo } from './foo' , ele emitirá import { Foo } from './foo.js' . Ele está disponível no NPM e as instruções de como usá-lo podem ser encontradas no leia-me do projeto.

https://github.com/Zoltu/typescript-transformer-append-js-extension

Se algo assim fosse integrado ao compilador TypeScript (como uma opção do compilador), provavelmente seria mais inteligente decidir quando anexar a extensão .js e quando não. No momento, ele procura qualquer caminho começando com ./ ou ../ e que não tenha . em nenhum outro lugar no caminho. Isso significa que ele não fará a coisa certa em vários cenários extremos, embora eu questione se alguém _realmente_ se deparará com esses casos extremos ou não.

@MicahZoltu ótimo ver soluções userland para isso. Eu acho que é muito importante, porém, que o modelo mental se torne sempre incluir extensões de arquivo , de modo que a opção de extensão TypeScript possa se tornar _transformar extensões .ts em extensões .js na compilação_. Isso evita os casos de borda de resolução, deixando apenas o caso de nomes de pacotes npm que terminam em ".ts", que podem ser tratados como discuti no meu comentário anterior.

@guybedford Incluir a extensão .js em um arquivo .ts faz com que o arquivo não possa ser executado em ts-node. Resolver o problema no ts-node está longe de ser trivial devido à maneira como o NodeJS faz a resolução de arquivos. Isso significa que, se você publicar uma biblioteca com extensões .js codificadas, a biblioteca não funcionará para ninguém usando ts-node. Veja a discussão sobre isso em https://github.com/TypeStrong/ts-node/issues/783.

@MicahZoltu Quero dizer incluir a extensão .ts em um arquivo .ts .

@guybedford Incluir a extensão .js em um arquivo .ts faz com que o arquivo não possa ser executado em ts-node.

Esta é mais uma razão pela qual a execução automática do TypeScript no nó e nos navegadores é uma má ideia.

@MicahZoltu Quero dizer incluir a extensão .ts em um arquivo .ts.

Eu acho que o problema com isso é que ele quebra a equivalência entre um arquivo .ts e um par .js / .d.ts . Isso significa que, se você estiver importando um arquivo compilado com o projeto atual, use .ts e, se mover o arquivo para um projeto diferente, precisará alterar as importações para ele para usar .js .

Isso também significa que a saída não funciona em ambientes padrão sem o transformador. Dado que não há como instalar um transformador a partir de um arquivo .tsconfig , isso significa que você sempre terá que usar um compilador personalizado. Essa é uma barreira muito grande para colocar em prática pelo pequeno benefício de usar .ts em vez de .js .

Isso significa que, se você estiver importando um arquivo compilado com o projeto atual, usará .ts e, se mover o arquivo para um projeto diferente, precisará alterar as importações para usar .js.

Os limites de importação externos/internos são coisas bem definidas. Se uma dependência passar de um arquivo .ts interno do mesmo build atual, para um arquivo .js externo de outro pacote de importação que tenha seu próprio build separado ou talvez até não seja TypeScript , então sim, você precisa alterar a extensão, pois é um conceito completamente diferente.

Isso também significa que a saída não funciona em ambientes padrão sem o transformador.

Embora um transformador possa nos ajudar a explorar isso, um sinalizador / opção de compilador --ts-to-js ou similar é muito necessário para resolver esse problema.

@guybedford Você me convenceu de que colocar .ts era a coisa certa a fazer para o plugin. No entanto, ao tentar implementá-lo, aprendi que o TypeScript não permite isso!

// foo.ts
export function foo() { console.log('foo') }
// bar.ts
import { foo } from './foo.ts' // Error: An import path cannot end with a '.ts' extension. Consider importing './foo' instead
foo()

Olá, e quanto a isso?


entrada:

// src/lib.js.ts
export const result = 42;
// src/index.js.ts
import { result } from "./lib.js";

console.log(result);

saída:

// build/lib.js
export const result = 42;
// build/index.js
import { result } from "./lib.js";

console.log(result);

edição nº 30076

Uma única extensão .ts em um arquivo TypeScript parece mais apropriada para mim. Muitas vezes você não sabe até o momento da compilação qual é o alvo. Por exemplo, em muitos dos meus projetos de biblioteca, tenho vários arquivos tsconfig.json que visam ambientes diferentes, como navegadores modernos que devem emitir arquivos .js e mapear caminhos de importação para .js , ou visando o Node moderno, que deve emitir arquivos .mjs e mapear caminhos de importação para .mjs .

@MicahZoltu que importar arquivos que terminam em .ts é um erro é possivelmente para nosso benefício, na verdade. Porque isso significa que a reescrita de extensão .ts a .js na compilação pode ser adicionada sempre que as extensões .ts forem usadas sem precisar de um sinalizador :)

Talvez um PR para habilitar extensões .ts sendo suportadas e reescritas para extensões .js (possivelmente sob um sinalizador para habilitar esse recurso, mas um sinalizador que possa ser removido a tempo) seria uma ótima maneira para começar por este caminho.

//cc @DanielRosenwasser

Esta questão já é muito longa, então alguém já deve ter dito isso, então corre o risco de repetir o que já foi dito:

O TypeScript deve permitir que os desenvolvedores especifiquem extensões em import s porque é JavaScript válido. E não se trata apenas da extensão JS/TS! No ESM, qualquer extensão é válida desde que o tipo MIME esteja correto.

import actuallyCode from './lookLikeAnImage.png';

…deve ser válido desde que o servidor sirva JavaScript válido nesse arquivo e defina o tipo MIME correto. Isso vai além, pois o mesmo pode ser verdade para o TS! Um arquivo TS pode ser apenas um código-fonte JS servido com o tipo JS MIME e, portanto, um caminho válido para uma importação de módulo ESM.

O IMO TypeScript deve considerar apenas as importações sem uma extensão (como você quer hoje) e deixar as que estão sozinhas, sem erro, aviso etc. Caso contrário, ele rejeitará o código JavaScript válido, o que é muito lamentável para algo que afirma ser um superconjunto de JS.

Desculpe se este não é o lugar certo para levantar isso, eu vi alguns outros problemas: #18971, #16640, #16640, mas os problemas neste tópico parecem estar sendo fechados à esquerda e à direita, então presumo que este seja o "principal" desde que foi autorizado a permanecer aberto.

Jogando com NodeJS v12.7.0

salathiel@salathiel-genese-pc:~/${PATH_TO_PROJECT}$ node --experimental-modules dist/spec/src/ioc
(node:15907) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/default_resolve.js:59
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot find module '${PROJECT_ROOT}/dist/spec/src/ioc' imported from ${PROJECT_ROOT}/
    at Loader.resolve [as _resolve] (internal/modules/esm/default_resolve.js:59:13)
    at Loader.resolve (internal/modules/esm/loader.js:73:33)
    at Loader.getModuleJob (internal/modules/esm/loader.js:149:40)
    at Loader.import (internal/modules/esm/loader.js:133:28)
    at internal/modules/cjs/loader.js:830:27
    at processTicksAndRejections (internal/process/task_queues.js:85:5) {
  code: 'ERR_MODULE_NOT_FOUND'
}
salathiel@salathiel-genese-pc:~/${PATH_TO_PROJECT}$ node --experimental-modules dist/spec/src/ioc.js
(node:16155) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/default_resolve.js:59
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot find module '${PROJECT_ROOT}/dist/spec/src/observe' imported from ${PROJECT_ROOT}/dist/spec/src/ioc.js
    at Loader.resolve [as _resolve] (internal/modules/esm/default_resolve.js:59:13)
    at Loader.resolve (internal/modules/esm/loader.js:73:33)
    at Loader.getModuleJob (internal/modules/esm/loader.js:149:40)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:43:40)
    at link (internal/modules/esm/module_job.js:42:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Agora, eu não sei por que isso é irritante ...

No momento, o TypeScript não reescreve caminhos. É definitivamente irritante, mas atualmente você pode adicionar a extensão .js você mesmo.

@DanielRosenwasser https://github.com/microsoft/TypeScript/issues/16577#issuecomment -309169829

Que tal implementar por trás de uma opção? Gostou --rewrite-paths ( rewritePaths: true )?

@viT-1 Aqui está uma solução alternativa por enquanto: https://github.com/microsoft/TypeScript/issues/16577#issuecomment -507504210

@MicahZoltu Acabei de resolver meu caso de uso pelo pacote SystemJS (opção tsconfig outFile)

Eu não li todos os comentários que as pessoas escreveram sobre isso, mas não sei entender por que tenho que escrever .js um zilhão de vezes. Eu quero que o computador faça isso por mim.

@richardkazuomiller Todos nós fazemos, mas @DanielRosenwasser declarou em https://github.com/microsoft/TypeScript/issues/16577#issuecomment -448747209 que eles não estão dispostos a fazer isso por enquanto (estou surpreso que este problema ainda esteja abertamente enganosamente por tanto tempo após a declaração acima). Se você quiser que o computador faça isso por você, considere usar um empacotador ou alguma ferramenta de terceiros para lidar com reescritas de caminhos de importação.

Quem quer que eu encerre esta questão?

Por favor, não feche, ainda estou esperando para ver como a equipe do TypeScript responderá a como eles abordarão as importações do ESM que permitem que qualquer extensão seja usada e dependa do tipo MIME. No momento, isso é possível em JavaScript, mas não em TypeScript. (Por favor, veja meu comentário anterior para detalhes.)

@TomasHubelbauer É por isso que propus um sinalizador no arquivo de configuração, ele pode indicar que todas as importações sem extensão devem ter a extensão .js (ou qualquer outra configurada) adicionada. Isso seria opt-in, portanto, o padrão pode ser falso, fazendo com que projetos existentes ou projetos com necessidades diferentes funcionem exatamente como estão.

Como dito anteriormente:

Não tenho certeza de qual versão do TS o adicionou, mas importações como ' ./file.js' agora funcionam (mesmo que o arquivo seja realmente file.ts).
O TypeScript resolve o arquivo corretamente e gera a importação .js completa para o destino.

Isso faz sentido porque qualquer JavaScript válido é TypeScript válido. Já que você pode fazer:

import foo from './bar.js'

...em JS, você também pode fazer isso em TS. Se você fizer isso, você resolverá o problema de usar módulos ES6 nativos porque suas extensões estão corretas.


Também não podemos esquecer que quando o navegador vê uma importação para ./foo/bar , ele realmente faz uma solicitação para isso. O fato de que nada foi servido foi devido ao servidor. Você pode configurá-lo de forma que as solicitações de /foo/bar sejam satisfeitas com /foo/bar.js . Não estou dizendo que esta é uma boa solução, ou mesmo uma boa ideia , mas tecnicamente funcionaria.

sinalizador no arquivo de configuração, pode indicar que todas as importações sem extensão devem ter a extensão .js (ou qualquer outra configurada) adicionada

Isso resolveria a grande maioria dos casos. A equipe do TypeScript estaria disposta a considerar um PR para essa opção de configuração?

O NodeJS agora _por padrão_ se comporta da mesma maneira que os navegadores quando se trata de resolução de módulo de caminho relativo. Ele não inferirá mais uma extensão .js por padrão. Isso significa que o comportamento atual do TSC resulta na emissão de JS inválido em todos os contextos de tempo de execução. Parece que esse problema deve ser resolvido agora, pois há clareza no comportamento do navegador e do NodeJS para o ESM.

https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm

O novo resolvedor para esm precisa de um novo modo de resolução - moduleResolution: node realmente é apenas o resolvedor cjs para o que agora posso chamar de "versões antigas do nó". Se você pretende segmentar o novo resolvedor de esm, precisaremos de um novo modo de resolução para corresponder de forma mais adequada. Especialmente porque o nó ainda suporta totalmente o resolvedor antigo em todas as configurações existentes. (Observe: tornar esse novo resolvedor _nosso padrão_ seria difícil)

Apesar! Embora haja _discordância_ sobre isso e _algumas pessoas optarão por declarar a opinião como fato_, ainda há um sinalizador --es-module-specifier-resolution=node que retorna o comportamento de extensão esperado e ainda pode se tornar o padrão - como dizem os documentos, apesar de não ser sinalizado , os módulos es no nó são _ainda experimentais por natureza_.

Além disso, como um lembrete para a solicitação original: não reescrevemos importações. Sempre. Em absoluto. Especificador em === especificador fora. Os especificadores descrevem a intenção estrutural e não é nosso objetivo mapear implicitamente de uma estrutura pretendida para outra. Você também pode pensar desta forma: Se você escrevesse const varFoo = "./Foo"; import(varFoo) , de alguma forma adicionaríamos a extensão lá, se necessário? Não - isso é ridículo - para lidar com todas as formas de entrada dinâmica, precisaríamos envolver a importação dinâmica em tempo de execução e, de repente, nos tornamos um carregador de módulo próprio, camada sobre o carregador de plataforma embutido. Em vez disso, forneceríamos um modo de resolução que errou apropriadamente quando você omitir a extensão (para a qual, obviamente, você já pode encontrar regras de lint).

Se você encontrar este encadeamento e _realmente quiser_ que suas fontes de entrada não tenham extensões e _realmente precisar_ que sua saída ainda funcione com isso ao direcionar (node ​​es) módulos, você deve fornecer feedback em https://github.com/ nodejs/modules/issues/323 com sua lógica, para que possa funcionar dessa maneira na própria plataforma de destino, pois é isso que adiamos.

de repente, nos tornamos um carregador de módulo próprio

O tsc não precisa ser um carregador de módulo funcional, não importa o quê? Você não pode verificar o tipo em uma importação se não encontrar o módulo de onde veio. Eu só quero ver todos os vários carregadores de módulo se comportarem de uma maneira amplamente compatível, ou pelo menos de uma maneira previsível diferente que seja razoavelmente fácil de acomodar.

O NodeJS agora, por padrão, se comporta da mesma maneira que os navegadores quando se trata de resolução de módulo de caminho relativo. Ele não inferirá mais uma extensão .js por padrão. Isso significa que o comportamento atual do TSC resulta na emissão de JS inválido em todos os contextos de tempo de execução.

Este não é outro motivo para usar apenas as extensões de arquivo .js em especificadores como o TypeScript já suporta? Isso resolve tudo, exceto que seria ótimo se tsc tivesse um erro em importações sem extensão.

O tsc não precisa ser um carregador de módulo funcional, não importa o quê? Você não pode verificar o tipo em uma importação se não encontrar o módulo de onde veio. Eu só quero ver todos os vários carregadores de módulo se comportarem de uma maneira amplamente compatível, ou pelo menos de uma maneira previsível diferente que seja razoavelmente fácil de acomodar.

Não pretendemos fornecer uma implementação de carregador de tempo de execução - apenas uma análise de tempo de compilação que reflita qualquer carregador de tempo de execução que você segmentar. Não podemos remapear todas as importações sem um componente de tempo de execução, que não temos, nem pretendemos ter.

O tsc não precisa ser um carregador de módulo funcional, não importa o quê?

Não em tempo de execução. tsc precisa entender como o tempo de execução escolhido resolverá os especificadores e implementará isso em tempo de compilação, mas o tempo de execução é puramente deixado para o ambiente.

Você também pode pensar assim: Se você escreveu const varFoo = "./Foo"; import(varFoo) de alguma forma adicionaríamos a extensão lá, se necessário?

@weswigham Este é um forte argumento em relação às importações dinâmicas, mas não _acho que você pode fazer isso com importações estáticas? Posso apreciar o argumento de que a estratégia deve ser a mesma para ambos, mas acho que vale a pena mencionar que as importações estáticas cumprem um papel muito diferente das importações dinâmicas e não acho que seja totalmente _irracional_ ter uma estratégia diferente para as importações estáticas reescrita de importação e reescrita de importação dinâmica.

Este não é outro motivo para usar apenas as extensões de arquivo .js em especificadores como o TypeScript já suporta? Isso resolve tudo, exceto que seria ótimo se o tsc tivesse um erro nas importações sem extensão.

@justinfagnani Existem dois problemas com isso:

  1. Um tempo de execução que executa TS nativamente (como TS-Node) não funcionará se você especificar extensões .js em suas importações.
  2. Você está mentindo para o compilador (IMO) se incluir extensões .js em suas importações.

Em relação a (2), se eu tiver dois arquivos TS a.ts e b.ts e a.ts fizer import ... from './b.js' , estou dizendo ao compilador" Eu tenho um arquivo irmão chamado b.js . Esta afirmação não é verdadeira. Para piorar as coisas, se você tiver .b.ts e b.js (que podem não ser os derivados um do outro), é agora fica ambíguo a qual você está se referindo _mesmo que você tenha incluído explicitamente uma extensão_.

Eu sou da opinião de que o usuário deve dizer ao compilador o que ele realmente quer (como usuário) e isso é "importar qualquer arquivo com o nome X e qualquer extensão" (no caso de import ... from './foo' ) ou "importar especificamente este arquivo" (no caso de import ... from './foo.ext' ). Se o compilador detectar que você está importando um arquivo TS e continuar a emitir um arquivo .js , acredito que o compilador deve atualizar a importação para importar corretamente o arquivo apropriado. Isso pode significar alterar .ts para .js na declaração de importação.

@justinfagnani Existem dois problemas com isso:

  1. Um tempo de execução que executa TS nativamente (como TS-Node) não funcionará se você especificar extensões .js em suas importações.

Este é um bug no TS-Node. Não está correspondendo ao comportamento de tsc .

  1. Você está mentindo para o compilador (IMO) se incluir extensões .js em suas importações.

Na verdade, é o oposto - você está dizendo a verdade sobre o que realmente será importado. Você _não_ estará importando um arquivo .ts , mas um arquivo .js . Também não deve haver diferença visível entre um par .d.ts / .js e um arquivo .ts . Eles são intercambiáveis. A única maneira correta de fazer isso é importar o arquivo .js - qual será o arquivo .ts após a compilação.

@justinfagnani

Também não deve haver diferença visível entre um par .d.ts/.js e um arquivo .ts

Isto não é sempre verdade. Você pode configurar seu servidor para atender a todos os JS, TS e DTS com um tipo JS MIME e, em seguida, importá-los separadamente em JavaScript e o tempo de execução os executará devidamente como JS. O ESM não se importa com extensões.

É por isso que acho que os usuários do TS devem ser forçados a incluir uma extensão .ts e sem extensão seria um erro, a menos que realmente importasse um arquivo sem extensão ou esse nome. E TS reescreveria as importações para .js na saída. E se existisse um arquivo JS (não um gerado pelo TS), isso também seria um erro.

Este é um bug no TS-Node. Não está correspondendo ao comportamento de tsc.

É uma limitação do carregador NodeJS, não um bug no TS-Node: https://github.com/TypeStrong/ts-node/issues/783#issuecomment -507437929

Isto não é sempre verdade. Você pode configurar seu servidor para atender a todos os JS, TS e DTS com um tipo JS MIME e, em seguida, importá-los separadamente em JavaScript e o tempo de execução os executará devidamente como JS. O ESM não se importa com extensões.

Estou muito ciente disso, mas o navegador também não executará o TypeScript. É quase universalmente verdade que o arquivo que o ambiente realmente carrega é um arquivo JavaScript.

Meu ponto, porém, é que, se você já tiver um par .js / .d.ts , digamos de um pacote de terceiros, e importe o arquivo .js , tsc veja o arquivo .d.ts e carregue os tipos. ou seja, um par .js / .d.ts _acts_ como um arquivo .ts , e é assim que deve ser, pois é assim que você pode portar transparentemente do JavaScript para o TypeScript sem alterar as importações dos arquivos que são portados.

Este é um bug no TS-Node. Não está correspondendo ao comportamento de tsc.

É uma limitação do carregador NodeJS, não um bug no TS-Node: TypeStrong/ts-node#783 (comentário)

Ainda é um bug que o TS-Node esteja divergindo do comportamento tsc . Isso cria arquivos .ts que não funcionam em tsc e TS-Node, e eu consideraria fortemente tsc como o definidor de padrões que o TS-Node deve seguir .

Meu ponto, porém, é que se você já tiver um par .js/.d.ts, digamos de um pacote de terceiros, e importar o arquivo .js, o tsc verá o arquivo .d.ts e carregará os tipos. ou seja, um par .js/.d.ts age como um arquivo .ts, e é assim que deve ser, pois é assim que você pode portar de forma transparente de JavaScript para TypeScript sem alterar as importações dos arquivos que são portados.

Se você carregar um _package_ externo, precisará de algum tipo de carregador de pacotes em tempo de execução (por exemplo, mapas de importação nomeados no navegador) que faça o mapeamento do módulo nomeado para o arquivo de ponto de entrada. No entanto, acho que seu ponto geralmente se mantém, no caso de você ter um par .js/.d.ts relativo. Estou em dúvida se nesse caso você deve fazer import ... from './foo.d.ts' ou import ... from './foo.js' .

O arquivo .d.ts é essencialmente um cabeçalho que descreve a estrutura que não contém informações sobre qual extensão ele mapeia (supondo que geralmente você não deve ter vários arquivos com o mesmo nome, mas extensões diferentes no mesmo local, e nós erro na compilação se você fizer isso) - ainda hoje, a "fonte" de tempo de execução associada pode ser .js ou .jsx (usando jsx: preserve ). Você não poderia, amplamente, substituir uma referência .d.ts por .js em uma importação no momento da emissão e assumir que funciona...

É importante exatamente que tsc não seja muito opinativo quanto ao amplo
premissas de construção e resolução.

Dado que é uma ferramenta múltipla em um limite complexo, seria esperado
essa configuração pode permitir que ele se comporte da maneira que os usuários desejam.

Houve um esforço muito deliberado para não expor as mudanças de resolução como
parte do processo de compilação tsc - isso por si só força a opinião sobre
usuários e causa atrito em seus fluxos de trabalho.

Na quarta-feira, 27 de novembro de 2019 às 16:48 Wesley Wigham [email protected]
escrevi:

O arquivo .d.ts é essencialmente um cabeçalho que descreve a estrutura que contém
nenhuma informação sobre de qual extensão ele mapeia (supondo que
geralmente você não deve ter vários arquivos com o mesmo nome, mas
ramais diferentes no mesmo lugar) - ainda hoje, o associado
"origem" de tempo de execução pode ser .js ou .jsx (usando jsx: preserve). Você poderia
não substituir a referência .d.ts por .js em uma importação no momento da emissão
e suponha que funcione...


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/microsoft/TypeScript/issues/16577?email_source=notifications&email_token=AAESFSQS2DQ23RR5KN3RTZ3QV3TLXA5CNFSM4DPRQTY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFK,2TPA#issuecomment-559ZLOORPWSZGOEFK,2TPA#issuecomment
ou cancelar
https://github.com/notifications/unsubscribe-auth/AAESFSUAP2YO23ZFHCOWVQLQV3TLXANCNFSM4DPRQTYQ
.

Não tenho certeza de como lidar com esse cenário, mas tinha uma dúvida relacionada à mesma coisa.

Eu tenho um mapa de importação como este no meu arquivo html:

<script type="importmap-shim">
      {
        "imports": {
          "@root/":"../../../",
         }
      }
</script>

E eu tenho meu arquivo ts onde estou importando um arquivo assim:

import '@root/components/page-main/page-main.js';

Agora, essa configuração funciona bem no navegador. Mas, como poderei navegar/usar no VSCode? Quero dizer, eu quero ctrl+clique na importação e navegue até o arquivo, obtenha o preenchimento automático, digite def, etc.

Além disso, considerando que tsc não reescreve extensões de importação de .ts para .js , existe alguma outra ferramenta/pacote recomendado que eu possa usar para fazer o mesmo em tempo de compilação? Obrigado.

(Estou usando https://github.com/guybedford/es-module-shims para módulos ES e importar mapas)

Mas, como poderei navegar/usar no VSCode?

Procure a opção do compilador paths .

Além disso, considerando que tsc não reescreve extensões de importação de .ts para .js , existe alguma outra ferramenta/pacote recomendado que eu possa usar para fazer o mesmo em tempo de compilação? Obrigado.

Basta usar .js e funcionará bem, mesmo se você estiver se referindo a um arquivo .ts no momento da compilação.

@tvvignesh https://github.com/Zoltu/typescript-transformer-append-js-extension/ para reescrever importações sem extensão para .js em tempo de compilação. Eu pessoalmente não sou um fã do "basta colocar .js em seus arquivos TS" porque seu código não será executado em ts-node se você fizer isso. Se você não precisar executar seu código no ts-node, usar .js funcionará.

Mas, como poderei navegar/usar no VSCode?

Procure a opção do compilador paths .

Além disso, considerando que tsc não reescreve extensões de importação de .ts para .js , existe alguma outra ferramenta/pacote recomendado que eu possa usar para fazer o mesmo em tempo de compilação? Obrigado.

Basta usar .js e funcionará bem, mesmo se você estiver se referindo a um arquivo .ts no momento da compilação.

Obrigado pela sua resposta rápida. Eu já tinha configurado a opção paths no tsconfig.json mas ainda não consegui navegar com ctrl+click.

Esta é a minha opção de caminhos em tsconfig.json

"paths": {
            "*": ["www/node_modules/*"],
            "@modules/*": ["www/node_modules/*"],
            "@root/*": ["www/*"]
        }

Basta usar .js e funcionará bem, mesmo se você estiver se referindo a um arquivo .ts no momento da compilação.

Isso é bastante impraticável quando existem milhares de importações.

O problema com "apenas use .js " é que, se o TypeScript emitir arquivos .mjs , seu programa não funcionará. Isso significa que você acaba em uma situação em que está escrevendo TypeScript que _ou_ funciona no navegador _ou_ funciona no NodeJS. Você não pode mais escrever TypeScript que funcione em ambos.

Acredito que o argumento aqui seja: "Isso não é culpa do TypeScript, é o navegador e o NodeJS divergindo".

O nó 13.2 suporta extensões .js perfeitamente.

@justinfagnani Para módulos ES? Achei que o NodeJS só carregaria os módulos ES se eles tivessem uma extensão .mjs , caso contrário os arquivos seriam tratados como CommonJS?

Acho que todo esse tópico está um pouco equivocado. Escrever explicitamente a extensão do arquivo resolveria todo esse problema. Se estiver importando um arquivo JavaScript, escreva a extensão .js. Se estiver importando um arquivo TypeScript, escreva a extensão .ts. Isso é permitido no padrão e o compilador TypeScript entende tudo igualmente bem. O único problema é que o compilador afirma que as extensões .ts são erros. Isso não afeta uma transpilação pura, mas é apenas um erro de tipo. O TypeScript deve corrigir isso, pois obviamente uma extensão de arquivo .ts é válida, pois estamos criando no TypeScript. Para contornar esse problema, o Deno.js possui uma extensão do VS Code: https://marketplace.visualstudio.com/items?itemName=justjavac.vscode-deno

Com o advento do WebAssembly, os aplicativos da Web começarão a importar cada vez mais tipos de arquivo. Será cada vez mais importante declarar explicitamente se você está importando um arquivo .wasm, .js, .ts, .rs, .c, etc.

Alguém realmente usou o script que eu escrevi?

https://github.com/microsoft/TypeScript/issues/16577#issuecomment -310426634

algum feedback se sim?

@QuantumInformation Não usei seu script, mas o plug-in do transformador TypeScript que escrevi faz basicamente a mesma coisa. 😊 https://github.com/Zoltu/typescript-transformer-append-js-extension/

Em primeiro lugar, não vou tentar novamente convencer o typescript a implementá-lo, entendi, você não fará isso.
Estou lendo os comentários e me perguntando: todas aquelas pessoas dizendo que adicionar .js aos caminhos resolverá tudo - você realmente não usa pacotes de terceiros? Como estou adicionando extensões às minhas importações corrigindo o que está em node_modules?

@MicahZoltu oh legal

O que você quer dizer? Você escreveria explicitamente a extensão do arquivo que está importando de node_modules, se estiver usando um caminho. Mas isso não seria uma importação simples geralmente de qualquer maneira?

Se você especificar o caminho relativo, ele não ficará vazio. No entanto estou falando de importações internas do pacote que estou importando, veja rxjs por exemplo.

@Draccoz Acredito que o ponto a ser feito é que, se alguém escreve TypeScript como import { ... } from './foo' e depois publica isso como um pacote NPM, um usuário não pode usar essa biblioteca diretamente em um navegador, mesmo que tenha como alvo os módulos ES. Acredito que o argumento da Microsoft aqui é que o pacote está errado se estiver distribuindo código como esse com a expectativa de que funcione em um navegador.

Você escreveria a extensão do arquivo que existe em node_modules. import * as stuff from 'rxjs/path/to/file.js'; se for um arquivo JavaScript e import * as stuff from 'rxjs/path/to/file.ts'; se for distribuído um arquivo TypeScript. Isso funciona agora se não me engano

@lastmjs Sim, mas e se rxjs/path/to/file.ts contiver import foo from './bar' ? Você não pode alterar isso, pois não pode modificar o arquivo, pois é uma biblioteca de terceiros.

É por isso que devemos pressionar para usar extensões explícitas em todos os lugares, mas sim, entendo seu ponto. Minha ferramenta (https://github.com/lastmjs/zwitterion) faz essa reescrita como uma solução temporária para os arquivos que deixaram extensões de fora.

Sim, meu ponto era exatamente isso - apenas adicionar extensões não corrigirá bibliotecas de terceiros que não podemos modificar, então isso não é solução.
Eu também entendo o ponto da Microsoft, portanto, não estou mais pressionando (além do fato de que manter esse problema aberto dá esperança desnecessária que impede que os mantenedores de pacotes apenas ajustem a compilação em vez de esperar que o TS resolva isso), seria ser incrível ter apenas o typescript como uma ferramenta de compilação e nenhuma outra dependência.

sim, mas claramente a esperança ainda é boa para muitas pessoas

image

Ainda assim, foi afirmado algumas vezes através desses comentários que NÃO será implementado, então por que mantê-lo aberto?

se alguém escreve TypeScript como import { ... } from './foo' e depois publica isso como um pacote NPM

Muitas pessoas estão publicando TS não compilados em pacotes NPM? Eu estava olhando para isso para meu próprio uso interno. Estou criando bibliotecas de código comum compartilhadas entre projetos e percebi que o NPM é uma maneira razoável de empacotá-los, e nossa equipe mudou para o TS exclusivamente, então ficaria feliz em evitar ter que compilar o deps. Mas parece que o caso de uso mais comum é construir o pacote para JS com tipos separados, então apontar modules ou main para o JS e types para os tipos.

Existe uma convenção para publicar TS não compilado no NPM? Se sim, isso está documentado em algum lugar? Entendo que isso está errando o OT do problema original, mas acho que é relevante para a resposta, porque precisamos saber se "TypeScript de terceiros" (pacotes) é um caso de uso / objetivo com suporte.

@thw0rted Desculpe por não ser claro, eu quis dizer:

... se alguém escrever TypeScript como import { ... } from './foo' e depois transpilar isso para JS usando TSC hoje e publicar esse JS como um pacote NPM ...

Se NÃO for implementado, deixarei para a MS encerrar o problema agora.

Ah, entendi agora. Sim, quando eu transpile (com target: ES2018 ) o JS emitido deixa a extensão fora da declaração de importação, mas funciona para mim porque o consumidor está colocando tudo pelo webpack/babel e deve estar preenchendo a extensão que falta para mim. Estou a par da velocidade agora. Nem me ocorreu que meu "pacote" não funcionaria nativamente no navegador sem uma viagem pelo webpack primeiro.

Sim, essa é difícil.

@thw0rted Eu não uso webpack/babel, portanto, resolver .js da caixa é um problema para mim.
Alguma solução/solução alternativa é configurar o servidor web para fontes de resolução padrão .

Desculpe se estou repetindo o que os outros disseram, mas isso é algo com o qual lido todos os dias, então gostaria de acrescentar mais um dos meus dois centavos não solicitados.

Eu sei que o TypeScript não precisa atender a nenhum ambiente específico (Node.js, Webpack, etc.), mas o fato é que existem muitos ambientes em que a extensão é sempre necessária, a menos que configurada de outra forma, então eu não t acho que eles devem ser ignorados. As importações não estão mais atrás de um sinalizador no Node e o caminho de importação deve corresponder ao nome do caminho da URL na web. Embora não haja necessidade técnica de ter .js no final de uma URL, esse é o padrão de fato.

Se o pessoal da Microsoft realmente quer que nenhuma extensão de arquivo seja o padrão, não discutirei sobre isso. Você provavelmente é mais inteligente do que eu, mas eu certamente ficaria mais feliz se, em vez de inferir se as extensões são necessárias ou não com base em outras importações no mesmo arquivo, isso pudesse ser definido em todo o projeto para funcionar para preenchimentos automáticos do Intellisense pela primeira vez importação adicionada a um arquivo!

Enquanto isso, alguém conhece algum plugin VSCode que corrija isso? Adicionar importação/extensões ao eslint é o melhor que pude fazer para lidar com isso.

Atualmente eu escrevo import linhas sem extensão .js, e então uso sed para adicionar extensão .js em arquivos de saída.
https://github.com/yoursunny/NDNts/blob/9f50fcec245b33c7649fa815bbb3dd404eee160e/mk/build.sh#L12 -L14
Eu tenho que excluir SourceMaps durante a compilação de produção, porque eles não corresponderiam mais após a modificação dos arquivos de saída.

Não consigo escrever a extensão .js em arquivos de origem .ts porque quebra ts-jest .
Embora seja possível executar o Jest em arquivos .js compilados, ele quebra o Coveralls .

@yoursunny Sim, sed é uma variante (eu também usei, mas prefiro substituir no arquivo por causa da configuração que pode ser configurada pelo mapeamento de arquivo importmap) para substituir strings em arquivos js gerados, mas não cheira bem =) adicionar extensões será um recurso/opção útil para ttypescript com plug-in de transformação (por exemplo , typescript-transform-paths por @MicahZoltu).

@richardkazuomiller esta parte não é verdade:

Se as pessoas legais da Microsoft realmente querem não ter extensão de arquivo, seja o padrão

Apenas TypeScript:

  1. Permite a resolução de módulo no estilo Node-require (eles devem expandir isso para permitir a resolução no estilo Node-import, que requer extensões de arquivo).
  2. Na mesma unidade de compilação, resolve arquivos .js para um par .js/.d.ts mesmo antes de serem gerados pelo compilador.
  3. Não modifica os especificadores de importação _de forma alguma, nunca_.

Então a solução para tudo isso é simplesmente importar os arquivos .js com a extensão .js . O TypeScript resolverá para o arquivo .ts correto e não modificará o especificador de importação, então as coisas funcionarão apenas em navegadores e Node >= 13.2.

@yourunny você registrou um bug contra ts-jest ? Eles estão divergindo do padrão TypeScript de fato aqui. Também parece ser um bug no Coveralls se ele não puder utilizar mapas de origem nos arquivos .js.

você registrou um bug contra ts-jest ? Eles estão divergindo do padrão TypeScript de fato aqui.

Não, porque não entendo completamente como funciona a resolução ts-jest.

Também parece ser um bug no Coveralls se ele não puder utilizar mapas de origem nos arquivos .js.

O Coveralls recebe um relatório lcov do meu processo de compilação e exibe a cobertura de código usando arquivos confirmados no GitHub.
Não confirmo os arquivos .js de saída no GitHub. Se eu executar testes de unidade em arquivos .js, o relatório lcov fará referência aos arquivos .js que não existem no GitHub.
Portanto, os macacões não conseguem localizar os arquivos de origem. Ele exibirá a porcentagem de cobertura, mas não poderá mostrar quais linhas não estão cobertas.

A nova era chegou!

O recém-lançado Node.js v13 e todos os principais navegadores oferecem suporte a módulos ES nativos prontos para uso, e seria ótimo para o TypeScript oferecer suporte a esses ambientes de maneira simples.

A solução mais simples para os casos de uso mais básicos (um site servido por meio de um servidor de arquivos estático simples) seria adicionar uma nova opção de compilador como "appendJsExtension": true ou similar.

@mjbvz O problema no repositório do VS Code que você fechou é um pouco diferente: trata-se de usar o preenchimento automático para adicionar instruções de importação automaticamente; quando o VS Code faz isso, adiciona a instrução de importação sem uma extensão .js , e é fácil ignorar isso até uma falha de tempo de execução.

No entanto, se o TypeScript adicionar uma opção como "appendJsExtension": true ou similar, isso não importará muito e poderemos escrever código TS sem .js na fonte.

Talvez o plug-in do VS Code deva ter uma opção para ativar/desativar a adição automática de extensões .js em instruções de importação preenchidas automaticamente?

@mjbvz O problema do VS Code / Intellisense está relacionado, mas não deve ser fechado como dupe. Se esse problema for encerrado como WONFIX, isso aumentaria a importância do problema do VS Code.

Estou vendo um ponto esquecido e não entendendo como as soluções em que a extensão JS é especial resolveriam isso: para o ESM, nenhuma extensão tem um status especial, mesmo arquivos sem extensão estão completamente bem, desde que o servidor os exiba no navegador com o tipo MIME de texto/javascript apropriado. Isso significa que códigos como:

import something from './javascript-code.png';
import something2 from './javascript-code2.js';
import something3 from './javascript-code3.ts';

Tudo isso é válido desde que os arquivos (independentemente de suas extensões) contenham código JavaScript e sejam exibidos ao navegador com o tipo MIME JavaScript.

Como o TypeScript deve ser um superconjunto de JavaScript de tipo seguro, não vejo uma maneira de permitir importações como as acima, porque o código é JavaScript válido e, se o TypeScript não o aceitar, ele deixa de ser um superconjunto seguro de JavaScript, não está correto?

Então, soluções em que a extensão JS está implícita ou a única permitida que eu não acho que pode cortar isso? Além disso, mesmo as extensões TS e DTS IMO não podem ter caixa especial, porque, embora normalmente não seja o caso, elas podem conter código JavaScript, não código TypeScript e servidor para o navegador como tal, sem nenhum problema no que diz respeito ao ESM , desde que sejam servidos com o tipo MIME correto.

Estou faltando alguma coisa nesta frente? É possível que o TypeScript não implemente suporte para extensões arbitrárias (incluindo ausentes) nas importações de código e é possível que o TypeScript continue assumindo extensões TS nas importações de módulos, considerando que file.ts e file (sem extensão) resultaria em um conflito?

Web e Service Workers também estão recebendo suporte para importação/exportação do Módulo ES .

Eu apoio e endosso totalmente a ideia do @trusktr de implementar sua ideia como uma opção de compilador. Não é que eu queira me livrar de bundlers como webpack e rollup. Mas acredito que um recurso como esse removerá muitos problemas e tempo gasto na configuração de bundlers, quando tudo o que você quer é compilar um projeto Typescript simples sem pular obstáculos ou usar soluções alternativas complicadas.

Por favor, considere isso como uma opção para o compilador Typescript. <3

Alguém conhece uma maneira de executar os arquivos js individuais compilados em um navegador sem webpack ou --outFile , usando qualquer tipo de sistema de módulo?

Meu problema é o seguinte: o projeto TypeScript bastante grande com o qual estou trabalhando leva cerca de 35 segundos para compilar com o webpack em um arquivo js empacotado usando ts-loader .
A única maneira de otimizar isso foi usando transpileOnly que reduziu o tempo de compilação para 20 segundos, mas ainda é lento e eu perco a verificação de tipos.
Livrando-me do webpack, eu poderia chegar a cerca de 14 segundos usando outFile, mas ainda é muito lento para mim. Usar incremental não fez nenhuma diferença.

A única maneira de conseguir alguns segundos de tempo de compilação foi emitindo 1 arquivo js por 1 arquivo ts e usando o sinalizador incremental . Nesse caso, imagino que o ts detecte e compile apenas os arquivos que realmente foram alterados. O problema é que não consegui executar isso em um navegador em nenhum dos destinos de módulo que tentei: system, amd, es6.
Estou usando paths mapeamento em tsconfig.json e nos arquivos js compilados os erros que estou recebendo estão principalmente relacionados a não conseguir resolver esses aliases.

Existe alguma maneira de conseguir isso?

@andrewvarga Atualmente, executo todo o meu TypeScript compilado diretamente no navegador sem empacotar ou compilar em um único arquivo. A maneira mais fácil de fazer isso é:

  1. Certifique-se de que todas as importações em arquivos TypeScript tenham a extensão .js .
  2. Execute um servidor dev que resolva importações de nomes de pacotes npm para dependências, se necessário. es-dev-server é o mais simples que eu conheço.
  3. Execute tsc --watch (certifique-se de que o módulo seja esnext no seu tsconfig)

É isso. Se você acabou de escrever a extensão .js para importações em seu TypeScript, não precisará de outras ferramentas para corrigir os arquivos para navegadores.

@justinfagnani companheiro, você esqueceu a informação mais importante - os tipos devem estar no formato jsdoc, qualquer abstração do tipo sobre JavaScript nativo fará com que o analisador falhe.

@Draccoz tsc produzirá JavaScript, não TypeScript.

@andrewvarga A maneira mais simples que conheço de transpilar sem empacotar é meu projeto Zwitterion . Ele foi projetado para substituir um servidor de arquivos estático, para que você não precise alterar a maneira como desenvolve. Você pode importar e exportar com extensões de arquivo explícitas (.js para JavaScript e .ts para TypeScript), mesmo em elementos de script. É muito eficiente, faz cache e recarrega automaticamente quando os arquivos são alterados. Você terá que confiar em seu editor para análise estática (erros de tipo) embora

@andrewvarga Eu uso https://github.com/Zoltu/typescript-transformer-append-js-extension/ e direciono módulos ES nativos que carregam em todos os navegadores modernos (exceto Safari, o novo IE).

Se suas dependências de tempo de execução do NPM forem bastante limitadas, você poderá carregá-las com es-modules-shim sem nenhum agrupamento. Você pode ver um modelo de reação que criei que mostra tudo isso funcionando em conjunto: https://github.com/Zoltu/react-es2015-template

O @MicahZoltu Safari tem suporte ao módulo ES, eu sei disso, com base na caniuse e na experiência pessoal: https://caniuse.com/#search =modules

@justinfagnani awww desculpe, perdi a parte "TypeScript compilado", pensei que você estivesse falando sobre o texto datilografado jsdoc.

Obrigado a todos pelas várias dicas!

O que eu descobri é que usando o módulo hard-source-webpack-plugin npm para webpack e transpileOnly: true nas opções do ts-loader reduziu o tempo de compilação para cerca de 4-5 segundos.
Isso, é claro, ignorará erros de digitação, portanto, é útil apenas para iterações rápidas de construção, tentando no navegador e confiando no IDE para quaisquer erros em potencial, mas acho que é muito útil durante o desenvolvimento.

Para obter os erros de TS e compilação rápida, ainda acho que a única maneira seria executar módulos no navegador, mas a falta de suporte para mapas de importação e extensões js dificultava isso.
@justinfagnani @MicahZoltu obrigado, vou tentar essas opções. Em geral, prefiro evitar usar mais um módulo npm, mas parece inevitável.

Eu tentei fazê-lo funcionar usando systemjs também, mas fiquei preso com mapas de importação ..

@andrewvarga Você pode tentar SystemJs pelo meu exemplo leve com importmap.
Você também pode tentar meu exemplo pesado - alternativa systemjs & esm, mas os importmaps esm não são suportados pelo nativo, e devemos resolver os módulos manualmente (gulp-replace), ou você pode tentar es-module-shims .

Então, se eu estiver usando tsc como meu único compilador, direcionando esnext ou es2015 como meu tipo de módulo. Existe alguma maneira de usar a saída diretamente no meu navegador?

https://github.com/alshdavid-sandbox/typescript-only-compiler

Se eu entendi o resto deste tópico corretamente, o Typescript deve ficar perfeitamente feliz em compilar seu código se você alterar esta linha para dizer from "./module.js" . Em seguida, o index.js compilado terá uma instrução de importação ES6 válida e tudo deverá funcionar.

Isso é, a menos que você importe alguma biblioteca que não saiba como ES Import ou não se importe: P.

Eu criei um plugin para Gulp que adiciona .js para importar caminhos de arquivos. (também uma resolução de caminho de bônus ts).

Eu usei o Gulp porque não conheço nenhum outro executor de tarefas que me permita essencialmente anexar uma etapa simples de pós-processamento ao compilador tsc (tanto no modo de observação quanto no modo normal). Webpack e rollup ambos exclusivamente empacotados, e eu quero emitir módulos es.

Funciona, mas é lento de assistir, pois parece reconstruir a coisa toda.

https://github.com/alshdavid-sandbox/typescript-only-compiler/tree/gulp

Isso está ficando mais importante à medida que a equipe do nó decidiu contra as importações sem extensão
https://github.com/nodejs/modules/issues/444

Adicionar mapas de importação também decidiu contra importações sem extensão
https://github.com/WICG/import-maps/issues/194

Se quisermos usar o módulo es compilado do typescript no navegador ou no nó, precisamos ter extensões adicionadas pelo typescript? (para módulos internos) e manualmente para módulos externos? @weswigham

@chyzwar novamente, se você simplesmente escrever as extensões .js em sua fonte TypeScript, a saída compilada terá as extensões corretas e os módulos funcionarão em navegadores e Node. Você não precisa de ferramentas de transformação adicionais ou de tsc para fazer qualquer coisa por você.

É mais simples para o desenvolvedor fazer o seguinte: Se for um arquivo fonte TypeScript, escreva uma extensão .ts. Se for um arquivo de origem JavaScript, escreva uma extensão .js. Isso também compilará e executará corretamente no navegador (.ts precisará de um tipo MIME de aplicativo/javascript). A extensão deve corresponder ao tipo de arquivo de origem. Os módulos tsc e ES podem lidar com isso (pelo menos os módulos ES no navegador, espero que o Node.js siga o mesmo)

@justinfagnani tsc está bastante feliz com isso, e é justo dizer "não é nosso problema" aqui, mas parece não haver consenso aqui sobre o que é certo,

Entre tsc, vscode, webpack e ts-node, nenhum pode realmente concordar bem com um padrão que agora está se tornando disponível nativamente (agora disponível no navegador e no nó).

Exemplo 1

Eu quero escrever um pacote javascript moderno, criá-lo em typescript e retirar os tipos para distribuição como um módulo ecmascript (retendo instruções de importação e exportação).

Exemplo 2

Estou construindo um site estático usando módulos no vscode, por padrão ele irá importar automaticamente sem uma extensão para cada primeira importação e você precisa ajustar isso manualmente.

Nesses casos, o tsc pode lidar com isso e até exportar arquivos descritores que suportam consumir a distribuição do módulo es do typescript com tipagens completas (incrível).

Mas se eu quiser executar o código de teste na fonte, eu poderia usar o ts-node, mas aqui o ts-node não está feliz.

Da mesma forma, o fato de que tsc, vscode e webpack evoluíram para fazer o seguinte:

  1. importações automáticas vscode sem uma extensão
  2. tsc reescreverá com prazer as importações para um arquivo js como significando o arquivo ts
  3. webpack faz várias mágicas aqui para extensões padrão para procurar

São todas as coisas que devem ser questionadas agora que quatro implementações (chrome, firefox, safari, node) todas esperam que o caminho de importação aponte para algo que possa resolver diretamente para um arquivo.

Adicionar .js a uma importação deve ser uma solução temporária, não uma solução definitiva. Se alguma coisa, parece um hack. Uma maneira de enganar o compilador. E tentar ser mais esperto que um compilador é uma ideologia horrível para seguir imho. Eu só posso imaginar o quão confuso isso deve ser para pessoas novas no Typescript. Uma linguagem que deve ajudar os desenvolvedores de Javascript a escrever código _melhor_.

Como várias pessoas já mencionaram, se você adicionar .js à importação, o TypeScript os produzirá e tudo funcionará (pelo menos dentro do seu código). Raciocinar que o tsc deve adicionar extensões porque elas não funcionam no navegador é como pedir ao TypeScript para corrigir erros de tempo de execução causados ​​​​pelo desenvolvedor - ok, mas por que o desenvolvedor não pode corrigi-los sozinho?
Não me interpretem mal, eu adoraria que tsc fosse minha única dependência de desenvolvimento, mas algumas coisas simplesmente não acontecem e vão ficar como um sonho.

Eu adoraria que tsc fosse minha única dependência de desenvolvimento, mas algumas coisas simplesmente não acontecem e vão ficar como um sonho.

Devo ter visto dezenas de comentários quase idênticos abrangendo vários anos no #3469, incluindo alguns da equipe Typescript. "É um verificador de tipos, deve fazer uma coisa bem, não espere que ele substitua toda a sua cadeia de ferramentas..." Demorou 3 anos, mas eles ainda adicionaram o modo de construção, porque um bom argumento foi feito de que era a direção certa a seguir.

Webpack e rollup ambos exclusivamente empacotados, e eu quero emitir módulos es.

@alshdavid Rollup pode funcionar para você se você definir o formato de saída para esm e definir preserveModules para true : https://rollupjs.org/guide/en/#preservemodules

talvez as importações "sem extensão" fossem um pecado original, não compatível com a maneira como os navegadores funcionariam

agora é hora de corrigir nosso código-fonte e incluir as extensões .js : descobrimos que quando você adiciona extensões .js ao seu código-fonte hoje, tudo funciona: o navegador está satisfeito, o texto datilografado é agnóstico e os empacotadores não se importam

então talvez sem extensão fosse uma falha em nosso código-fonte que nossas ferramentas antigas estavam compensando

Escrever a extensão .js em importações no código-fonte datilografado é um completo absurdo. Está funcionando, preserva a extensão na saída, mas provavelmente falhará com erros "não foi possível resolver o arquivo" nas regras ESLint (ou TypeScript) no VSCode ou em qualquer editor que você esteja usando. Sem mencionar quando você está testando contra esse código-fonte datilografado. Então a ferramenta de teste também deve saber sobre esse comportamento de merda. Tenho quase certeza de que lançará erros que não podem resolver arquivos.

Exemplo básico

src/index.ts
src/foo.ts
test/index.ts

src/foo.ts

export default (a: number) => a + 100;

src/index.ts

// okay, editor (without ESLint) doesn't report error here
import foo from './foo.js';

export default () => {
  console.log(foo(123));
}

teste/index.ts

// errm... ts or js ext?! .ts should be the one that make sense
// and that's how the testing too will expect it to be, otherwise will throw
// but then it will detect some weird `.js` ext in the source files...
// which again won't be able to resolve... complete bullshit. 
import main from '../src/index.ts';
import foo from '../src/foo.ts';

test('some boolshit', () => {
  main();
});

test('about foo', () => {
  foo(20);
});

Desculpe o uso de "besteira", mas essa é a verdade.

Eu não acho que seja tão difícil implementar a opção básica que quando o compilador vê a extensão ( .ts ) nas importações para convertê-la em .js (ou mesmo opcionalmente permitir especificar qual a saída ext para estar). Quando não há extensão, não preserve as extensões (comportamento semi-atual?).

Escrever extensão .js em importações em código fonte typescript é um completo absurdo. Está funcionando, preserva a extensão na saída, mas provavelmente falhará com erros "não foi possível resolver o arquivo" nas regras ESLint (ou TypeScript) no VSCode ou em qualquer editor que você esteja usando.

Isso simplesmente não é verdade. ESLint, TypeScript, VS Code e todas as outras ferramentas relacionadas ao TypeScript que usei _apenas trabalho_ com esse método. Não é um hack, e tem uma lógica muito razoável em torno disso: que o arquivo que você está importando na verdade _é_ o arquivo .js e que suas extensões não devem ser alteradas apenas porque um arquivo importado faz parte do arquivo local projeto, ou pré-compilado como parte de um pacote de terceiros.

Novamente, escrevo todo o meu código TypeScript dessa maneira e resolve todos os problemas que são levantados neste tópico. A saída funciona muito bem em navegadores e Node. Não é besteira, apenas funciona, _hoje_.

Não, não é. Pelo menos no caso mais comum onde o diretório de saída é dist ou build ou lib e etc. Seus arquivos compilados não estão no mesmo diretório, eles simplesmente nunca existem lá (em src/ ) - nem durante o teste, nem durante a codificação no editor.

Ter/ver e importar ./foo.js no src/index.ts acima não faz NENHUM sentido para mim - a menos, é claro, se você realmente pretende importar o arquivo js/json, o que é completamente correto. Mas escrever ./foo.js quando você realmente quer dizer um outro arquivo de fonte typescript ( ./foo.ts ) é... brutal. É enganoso e confuso, e definitivamente errado.

Tenho quase certeza que se eu executar o test/index.ts acima com o Jest, ele falhará com o erro de não encontrar/resolver ./foo.js porque há apenas ./foo.ts .

Se deixarmos tudo de lado, por que é permitido ter a extensão .js mas não .ts uma (ts reportar erro no editor)? É uma inconsistência básica, simples e estúpida. Como muitos outros problemas "só porque" no TypeScript.

Na verdade, perdi a lógica de por que esse problema é nomeado dessa maneira quando é realmente possível terminar com a extensão .js . Eu acho que o problema é o oposto - que não pode terminar com .ts (a partir de 3.7+)

por que a extensão .ts nas importações é totalmente proibida?!

E vamos esclarecer. Estou falando de tempo de desenvolvimento e experiência. Estou entendendo por que podemos preservar a extensão .js na saída compilada e por que podemos adicionar .js ext às importações em um arquivo .ts sem relatar erros, e eu estou bem com isso.

TypeScript é um superconjunto de JavaScript, mas não é JavaScript. JavaScript é um destino de compilação para TypeScript.

Com isso em mente, apesar do conhecimento de que o TS compilará para JS, eu esperaria que o código TypeScript se comportasse em uma mansão totalmente independente.

Escrever um .js ao tentar importar um arquivo .ts pressupõe o conhecimento do tipo de compilação de destino e assume que o destino de compilação é sempre JavaScript.

E se compilarmos o TypeScript para um binário de montagem da Web ou executarmos o código TypeScript usando um tempo de execução alternativo, como Deno ou ts-node.

Instruções de importação que terminam com .js não fazem sentido em tais contextos.

Prefiro ser forçado a digitar .ts nos meus caminhos de importação ou não ter uma extensão especificada assumindo um arquivo de origem TypeScript.

É triste que o texto datilografado tenha inventado sua própria extensão em vez de ser apenas um açúcar de sintaxe como o fluxo.

@phaux Eu nunca gostaria de trabalhar com um projeto, que mistura arquivos source e dist na mesma extensão, mesmo que eles morem em pastas diferentes. É como nomear todos os arquivos index.js só porque eles vivem em pastas diferentes...

Esse problema (que é maior que o TypeScript) parece impedir que o IntelliSense do Visual Studio Code funcione em navegadores da Web e Node - o que requer caminhos de arquivo completos (relativos) em especificadores de importação. Sem isso, as instruções import geradas que ele cria só funcionam com transpiladores e empacotadores, como o WebPack e o próprio TypeScript.

A resposta da equipe do VSCode foi que as extensões deveriam ser adicionadas pelo código que fornece sugestões de importação automática. Suspeito que seja o TypeScript Language Server (não tsc , sobre o qual a discussão aqui foi).

Alguém que realmente conhece as coisas pode confirmar (ou corrigir) que o VSCode obtém sugestões de importação automática do TypeScript Language Server?

a situação é um pouco complicada e cheia de nuances, então enquanto as extensões ".js" inicialmente vão contra as intuições e ideais elegantes de muitas pessoas, pode ser imprudente e confuso para o texto datilografar se desviar muito dos padrões ratificados do navegador e das implementações enviadas

então talvez consideremos o paradigma atual da seguinte forma:
as importações do typescript descrevem o que é importado em tempo de execução – ou seja, suas importações estão sendo executadas em seu diretório "dist", não em "src" – como chamadas fetch e o resto – se pudermos tolerar essa ideia, o resto se torna simples e consistente

parece certamente uma má ideia ter o typescript anexando cegamente ".js" a importações sem extensão como o node faz para commonjs (vale a pena notar que o suporte a node esm requer ".js" da mesma forma que o typescript hoje) - anexando cegamente ".js" criaria novos problemas, como importar arquivos javascript verdadeiramente sem extensão, ou até mesmo outros tipos de arquivo como css ou json – tornaria as extensões significativas e exigiria uma lógica de análise especial, criando uma diferença gritante entre a semântica do navegador e do typescript – e obviamente não vamos reescrever fetch chama da mesma maneira, então talvez import deve permanecer semelhante?

no entanto, eu me pergunto - é relativamente inofensivo para typescript converter extensões ".ts" para ".js"?

é claro, isso tornaria impossível importar um arquivo javascript que tivesse uma extensão ".ts" – mas talvez isso seja um pouco de magia funky que possamos tolerar? por outro lado, é uma diferença idiossincrática mágica e funky entre a semântica do navegador e datilografada que os desenvolvedores teriam que aprender e entender (certamente criando estranhas pegadinhas) - então meu instinto é deixar as coisas onde estão hoje

por outro lado, se mantivermos as coisas como estão, a mágica é simplesmente realocada para o texto datilografado, que deve relacionar as importações ".js" aos arquivos de origem ".ts" correspondentes – isso me parece um local mais razoável para abrigar a magia, sendo interno ao texto datilografado em vez de atropelar a semântica do navegador

🥃 perseguir

@rconnamacher , @TomasHubelbauer

Esse problema (que é maior que o TypeScript) parece impedir que o IntelliSense do Visual Studio Code funcione em navegadores da Web e Node - o que requer caminhos de arquivo completos (relativos) em especificadores de importação. Sem isso, as instruções de importação geradas por ele só funcionam com transpiladores e empacotadores, como o WebPack e o próprio TypeScript.

eu acho que há apenas alguma confusão aqui - é muito possível hoje criar uma biblioteca ou aplicativo datilografado que funcione muito bem com vscode e intellisense, que funcione em navegadores e nodos e funcione em esm ou commonjs - uma solução verdadeiramente universal é possível hoje

eu tenho trabalhado em um punhado de bibliotecas abertas que exibem isso - renraku , cynic , redcrypto , autoritarian

envie-me um e-mail e eu ficaria feliz em explicar mais

:onda: perseguir

Outro ponto é que resulta em confusão em qual arquivo você está acessando. Já existe uma ambiguidade do que tsc olha após a resolução do módulo quando você tem um arquivo .js e .ts lado a lado.

/folder
  a.ts
  a.js
  index.ts

Se em index.ts , ao usar moduleResolution: 'node'

// points to a.ts
import * as a from './a` 

// points to a.ts
import * as a from './a.js` 

// compiler emits error
import * as a from './a.ts` 

Já existe uma ambiguidade sobre o que o tsc analisa após a resolução do módulo quando você tem um arquivo .js e .ts lado a lado.

OK, claro, mais ou menos, mas se a.js for qualquer coisa menos a versão transpilada de a.ts , então algo deu catastroficamente errado e não é culpa do TypeScript.

@thw0rted se você estiver compilando para um único arquivo de pacote JS, o TypeScript não gerará uma contraparte JS para os arquivos TypeScript de entrada, apenas o arquivo de pacote único. Nesse caso, é completamente legal ter um arquivo JS para e um arquivo TS com o mesmo nome que não correspondam de forma alguma.

Não é "ilegal", mas isso não significa que seja uma boa ideia. Você tem um exemplo concreto de onde você realmente quer isso?

Seria simplesmente bom usar o TypeScript sem bundlers, loaders e de uma forma que emita JavaScript que pode ser usado diretamente por navegadores modernos.

Como um exemplo:
https://github.com/alshdavid/tsc-website

Mas eu sinto a dor do problema. A equipe do TypeScript não deseja implementar a resolução do módulo. É o mesmo motivo pelo qual o compilador TypeScript não pode converter paths em seus caminhos relativos reais em tempo de compilação.

Converter uma importação de .ts para .js ou adicionar .js a uma importação sem uma extensão significa que a equipe do TypeScript estaria implementando a resolução do módulo e isso está fora do escopo.

Uma solução para isso é a equipe do TypeScript fornecer uma maneira de introduzir extensões para que possamos implementar essas coisas.

Uma solução para isso é a equipe do TypeScript fornecer uma maneira de introduzir extensões para que possamos implementar essas coisas.

Eles fazem, apenas não é exposto via tsc (somente via invocação programática do compilador). Felizmente, alguém construiu um wrapper em torno do compilador principal que funciona _exatamente_ como tsc , exceto que suporta extensões via configuração. Usando este wrapper tsc, você pode usar uma extensão como https://github.com/Zoltu/typescript-transformer-append-js-extension/ para adicionar automaticamente a extensão .js .

@alshdavid seu exemplo no GitHub funciona em navegadores sem um empacotador se você incluir a extensão .js nas importações. Eu arquivei um PR para corrigi-lo.

@alshdavid Pode ser interessante no meu projeto de amostra (esm para moderno e IE11 com SystemJS ).
Mas sou forçado a resolver os módulos esm manualmente =(

Não tenho nenhum problema em princípio em colocar .js em todos os meus import s, mas infelizmente isso expõe uma interação ruim com algumas ferramentas. Por exemplo, ts-node engasga: https://github.com/TypeStrong/ts-node/issues/783. Não parece haver um acordo claro sobre de quem é a responsabilidade - TypeScript para emitir a extensão .js (em algumas circunstâncias) ou todas as ferramentas que consomem fontes TypeScript para fazer a tradução. E enquanto todos estão passando a responsabilidade, os usuários estão sofrendo com plugins mal documentados ou trabalhadores de serviço desajeitados para contornar as incompatibilidades de interoperabilidade.

Existem atualizações sobre isso? Sinceramente, não posso acreditar que não parece ser possível usar o TypeScript normalmente hoje sem um carregador de módulo externo ou empacotador como o Webpack. Isso parece tão estranho e também frustrante para mim. Se eu tiver que usar algum módulo externo para fazer o TypeScript funcionar totalmente, isso deve ser iniciado.

Estou tentando usar isso no meu aplicativo Electron e é por isso que não vejo um motivo para usar um empacotador da Web e também gostaria de não instalar um carregador de módulo externo se não for necessário. Mas isso está me deixando louco. Nem mesmo sendo capaz de obter uma configuração básica do TypeScript + Electron, embora ambos sejam elogiados em todos os lugares como sendo a melhor solução disponível. Isso é loucura, para ser honesto. Não sei se estou apenas perdendo alguma coisa, mas não conseguir encontrar uma solução adequada é mais do que frustrante.

E se realmente não sou eu, não entendo por que esse problema não foi corrigido em 3 anos ...

Recentemente, concluí o tutorial datilografado e, quando tentei criar alguns arquivos ts, deparei com esse problema. Eu sou completamente novo neste mundo js-ts, então me perdoe se algo estiver errado ou enganoso/mal informado.

o que eu fiz foi, ao importar

Acabei de colocar a extensão .js no arquivo ts e, quando verifiquei o intellisense, funcionou também quando o transpilei usando tsc, ele adicionou a extensão .js também ao arquivo de saída gerado.

Segue o que eu fiz.
tsc -p tsconfig.json

{
"compilerOptions": {
//"módulo": "amd",
"módulo": "es6",
"alvo":"es6",
"noImplicitAny": falso,
"removeComments": true,
"preserveConstEnums": false,
//"outFile": "js",
"outDir":"js",
"sourceMap": falso
},
"incluir": [
"testscript.ts"
]
}

Embora tenha funcionado para mim.

Minha dúvida é que, como não há svgwrapper.js para importar
por que/como funcionou? (Estou assumindo que não considera extensão)

Estou anexando a captura de tela para referência.

ts-js-ext-issue

@yogeshjog é exatamente assim que tsc é e deve funcionar. Você importa o módulo com o nome do arquivo que será gerado. Se o módulo importado é originalmente escrito como um arquivo .ts ou um par .d.ts / .js não deve ser observável a partir do módulo importador.

@yogeshjog é exatamente assim que tsc é e deve funcionar. Você importa o módulo com o nome do arquivo que será gerado. Se o módulo importado é originalmente escrito como um arquivo .ts ou um par .d.ts / .js não deve ser observável a partir do módulo importador.

Obrigado! @justinfagnani pelo esclarecimento 👍

Você importa o módulo com o nome do arquivo que será gerado.

Mas o TypeScript também permite omitir a extensão, o que não é permitido de acordo com o ECMAScript. Ele até omite a extensão ao usar o recurso de importação automática no VSCode, que é a coisa mais irritante. Você escreve algum JS e o TS diz que está tudo bem e depois trava no tempo de execução.

Mas o TypeScript também permite omitir a extensão

Ao usar a resolução do nó. tsconfig está pelo menos configurado para permitir outros modos de resolução que avisariam sobre isso, mas meu entendimento é que a equipe está permitindo que o suporte ao módulo nativo se estabeleça antes de adicionar mais modos.

que não é permitido de acordo com ECMAScript.

ECMAScript não diz nada sobre especificadores de importação. Isso é deixado para hospedar ambientes como HTML e Node. O TypeScript oferece suporte à resolução de nó ao carregar módulos e interpreta a resolução em relação ao compilador _output_, não ao compilador _input_. Dessa forma, os especificadores funcionam após a compilação e funcionam independentemente de você estar tentando importar um módulo compilado ou não.

Como o TypeScript usa a resolução Node, que fará uma pesquisa de caminho para transformar './foo' info './foo.js' , './foo' é válido. Mas a resolução do nó não transformará './foo.ts' em './foo.js' , portanto './foo.ts' é inválido.

Mas isso está dentro da resolução do Node. Se você estiver tentando usar outro ambiente como HTML ou suporte a módulo nativo do Node, o TypeScript e o host discordarão sobre o que é válido.

Espero que o suporte ao módulo nativo esteja resolvido o suficiente agora para o TypeScript adicionar outra configuração de resolução.

@leontepe Você não precisa de um empacotador/carregador. Você pode usar https://github.com/Zoltu/typescript-transformer-append-js-extension/ (minha solução preferida) ou pode anexar .js a todas as suas instruções de importação (cuidado: isso faça seu código falhar em ts-node ).

@leontepe Você não precisa de um empacotador/carregador. Você pode usar https://github.com/Zoltu/typescript-transformer-append-js-extension/ (minha solução preferida) ou pode anexar .js a todas as suas instruções de importação (cuidado: isso faça seu código falhar em ts-node ).

@MicahZoltu Bem, obrigado, mas ainda é meio frustrante que não funcione apenas 'fora da caixa'. Como o @phaux disse, o VSCode sugere que seus usuários façam declarações de importação sem a extensão e isso simplesmente não funciona em tempo de execução. Eu questiono seriamente a competência da equipe TypeScript aqui ou errei em algo o tempo todo e sou simplesmente estúpido. Mas quem sabe...

Edit: considerando seriamente apenas descartar o TypeScript para JavaScript + Babel neste momento.

Eu não escrevi um aplicativo Electron, mas existe alguma possibilidade de fazer com que ele faça uma resolução no estilo Node, onde existe um algoritmo para tentar resolver importações que tenta várias coisas em uma ordem fixa? Parece que deve estar tudo bem, já que todas as fontes estão sendo carregadas de recursos locais ...

Talvez seja hora de adicionar uma nova resolução de módulo ao TS? O Node.js tem suporte nativo ao ESM agora, mas sem extensões explícitas nos caminhos relativos ele força a usar o sinalizador --experimental-specifier-resolution=node , o que é meio chato. Há também Deno e navegadores. O ideal seria algo assim:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

então Texto datilografado:

import foo from './foo.ts'; // no ts(2691) here

compila para Javascript:

import foo from './foo.js';

"strict": true significa muito trabalho!
2020, ainda não consertado, ridículo.

Apenas entrando na conversa para dizer que esse problema também está bloqueando nossa equipe 😢

Gostaríamos muito de poder ter uma única fonte que compilasse em módulos nativos e também fosse consumível em node e com webpack. O Webpack parece ter um problema se você inserir .js manualmente em suas importações em seu código TS. No entanto, você pode fazer o webpack funcionar se colocar a extensão de arquivo .ts em suas importações, mas é claro que o typescript reclama. Não ter uma extensão de arquivo resulta em não ter módulos nativos. Portanto, nenhuma combinação parece satisfazer o navegador e os empacotadores. Se pudéssemos escrever .ts em nossas importações e torná-lo .js na saída, o problema seria resolvido, acredito (e você também obteria deno compat). Algo como @evg656e sugere parece que deve funcionar.

@EisenbergEffect existe um bug arquivado contra o WebPack para isso? Realmente parece um problema do WebPack estar divergindo do tsc normal.

@justinfagnani Não tenho certeza se o problema está no webpak, ts-loader ou em outro lugar. Passei muito tempo tentando colocar minha configuração de compilação ideal no lugar e não encontrei nenhuma solução que marcasse todas as caixas. Provavelmente existem maneiras de fazer isso com transformadores personalizados ou etapas pós-construção, mas estou relutante em adotar configurações não padrão, pois isso pode afetar negativamente os desenvolvedores de downstream.

@EisenbergEffect se o carregador TypeScript do WebPack não permitir que você importe arquivos TypeScript por meio de uma extensão .js como tsc , então é um bug. Como você disse, o comportamento impede que a mesma fonte seja compilada com WebPack e tsc .

Talvez seja hora de adicionar uma nova resolução de módulo ao TS? O Node.js tem suporte nativo ao ESM agora, mas sem extensões explícitas nos caminhos relativos ele força a usar o sinalizador --experimental-specifier-resolution=node , o que é meio chato. Há também Deno e navegadores. O ideal seria algo assim:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

então Texto datilografado:

import foo from './foo.ts'; // no ts(2691) here

compila para Javascript:

import foo from './foo.js';

As pessoas (por exemplo, eu) adorariam deixar um pedaço de código funcionar entre Node.js, Deno e a Web ao mesmo tempo. Acho que isso seria um grande marco para a programação TypeScript/JavaScript.

Se você estiver usando vscode e precisar de uma solução provisória, adicionar isso a settings.json parece corrigir os problemas:

"typescript.preferences.importModuleSpecifierEnding": "js"

Ele anexará .js aos seus caminhos de importação (o que resolverá os arquivos *.ts em src sem erros, mas reterá o .js ao transpilar). É útil ao usar tsc sem um bundler.

Enquanto esperamos por uma solução tsc, uma solução de baixa tecnologia para isso é

  1. Copie todos os arquivos de origem para uma pasta temporária
  2. Remova a extensão para importações e exportações antes de compilar

Eu queria compartilhar este one-liner caso outros possam usá-lo. Ele copia a pasta src/ para tmp/ e altera os arquivos lá.

npx shx cp -r ./src/ ./tmp/ && npx rexreplace "(^§s*?(?:import|export).*?from§s+?(['\"]).*?)§.ts§2" €1€2 './tmp/**/*.{ts,js,tsx,jsx}'

Como parte de um script de compilação em package.json (depois de fazer um yarn add --dev shx rexreplace ) pode ficar assim

"scripts":{
  "build": "yarn build-esm && yarn build-tsc",
  "buil-esm": "...Whatever you normally do...",
  "build-tsc": "shx mkdir -p tmp && shx cp -r ./src/* ./tmp && rexreplace \"(^§s*?(?:import|export).*?from§s+?(['\\\"]).*?)§.ts§2\" €1€2 './tmp/**/*.{ts,js,tsx,jsx}' && tsc src/index.ts && shx rm -r ./tmp"
}

Atualmente, mantenho .js fora dos caminhos de importação em fontes TypeScript, para manter Jest feliz.
Então, eu tenho uma etapa de pós-processamento para adicionar .js .
Os mapas de origem não são compatíveis com este método.

tsc -b tsconfig-solution.json -w --listEmittedFiles \
  | node mk/build-post.js

O script de pós-processamento build-post.js faz o seguinte.

Anexar .js a import e export de caminhos relativos

Por exemplo,

export { X } from "./first";
import { Y } from "./second";

torna-se

export { X } from "./first.js";
import { Y } from "./second.js";

Observe que eu não uso index.ts em nenhum lugar, mas sim mod.ts seguindo a convenção Deno. Assim, não preciso considerar o caso de anexar /index.js .

Altere import para require para pacotes CommonJS

Meu código roda no Node ^12.17 e ^14.1, no modo de módulos. Eu só publico Módulos ES.
No entanto, muitas dependências ainda possuem CommonJS em seu campo "main" .
Assim, devo alterá-los para CommonJS, exceto os módulos internos do NodeJS.

Por exemplo,

import { Server as WsServer } from "ws";

torna-se

import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { __importDefault } = require("tslib");

const { Server: WsServer } = require("ws");

Mas então, o webpack está insatisfeito com esses require s, então eu tenho que usar:

/// #if false
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { __importDefault } = require("tslib");
/// #endif

/// #if false
const { Server: WsServer } = require("ws");
/*
/// #else
import { Server as WsServer } from "ws";
/// #endif
/// #if false
*/
/// #endif

No webpack, qualquer pacote importando meu projeto deve usar ifdef-loader , e então o webpack veria a linha import original.

Também estamos sendo atingidos por isso e não consigo entender como isso não foi corrigido 3 anos depois de ser relatado.
Estamos usando o WebStorm para que a configuração específica do VSCode não funcione.
Usar um script separado para corrigir a saída é ridículo.
Isso deve funcionar sem ter que usar ferramentas de terceiros.

+1

Esta é a minha solução usando um site asp.net core 3.1 (provavelmente funciona em versões inferiores)
No startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            var rewriteOptions = new RewriteOptions();
            rewriteOptions.AddRewrite(@"^js/(.+)", "js/$1.js", skipRemainingRules: true);

            app.UseRewriter(rewriteOptions);

            app.UseStaticFiles();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }

O middleware de reescrita adicionará a extensão ".js" a qualquer solicitação direcionada à pasta /js.
Atenção: a ordem do middleware importa aqui, o UseStaticFiles deve ser colocado após o UseRewriter ou não funcionará.

Como todos aqui, eu preferiria uma solução pronta para uso, mas até lá...

Talvez seja hora de adicionar uma nova resolução de módulo ao TS? O Node.js tem suporte nativo ao ESM agora, mas sem extensões explícitas nos caminhos relativos ele força a usar o sinalizador --experimental-specifier-resolution=node , o que é meio chato. Há também Deno e navegadores. O ideal seria algo assim:
tsconfig.json:

{
    "compilerOptions": {
        "moduleResolution": "explicit",
        "strict": true
    }
}

então Texto datilografado:

import foo from './foo.ts'; // no ts(2691) here

compila para Javascript:

import foo from './foo.js';

Eu configurei a regra node/file-extension-in-import em eslint-plugin-node para linting config com a ideia de adicionar manualmente a extensão para importar declarações (pois é melhor assim) e o "moduleResolution": "node" no TypeScript config e tudo o que posso ver é ts(2691) .

Espero que valha a pena implementar o que @evg656e disse.

Eu não posso acreditar que isso ainda é um problema.

quando você usa
"baseUrl": ".", "paths": { "/*": ["./*"] },

você pode fazer uma importação de módulo absoulte assim:
`importar ws de "/hey/connection";

mas ao adicionar a extensão ".js", de repente o compilador não encontra mais a declaração connection.ts e diz:

Could not find a declaration file for module '/hey/connection'. '/home/tobi/Documents/JITcom/Code/Libs/Test_Browser/hey/connection.js' implicitly has an 'any' type.

usando um caminho relativo, tudo funciona bem.

Por favor, corrija isso

Também estou querendo uma correção para isso.

Obrigada.

É ridículo que isso ainda seja um problema! :00

Finalmente decidi mudar para o TypeScript e esse foi um dos primeiros problemas que encontrei. Ele quebra a resolução do módulo na implementação nativa do Node, e eu só consegui contornar isso usando o pacote esm que parece ser mais flexível em aceitar nomes sem extensões ou (estranhamente) usando extensões .js nos caminhos de importação dentro de meus arquivos .ts mesmo quando a importação está se referindo a um arquivo .ts ou .tsx. Não sei por que o compilador TypeScript aceita isso, mas pelo menos a saída da compilação inclui a extensão .js. Solução terrivelmente hacky embora.

Eu nem estou usando muito o typescript no lado do cliente hoje em dia, não afetou muito a qualidade do meu código e tornou as coisas muito mais simples. Provavelmente o JavaScript terá tipos opcionais de um ponto e esse problema não importará mais.

Deixo de fora a extensão nas linhas de importação, para deixar o Jest e o Webpack felizes.
Quando compilo, invoco tsc --listEmittedFiles e canalizo a saída para um script de pós-processamento. Esse script adiciona as extensões .js , para deixar o Node (no modo de módulo) feliz.
https://github.com/yoursunny/NDNts/blob/fa6b2eb68a9f32a6a2e24e5475275f803236b8f8/mk/build-post.js

@kj

(estranhamente) usando extensões .js nos caminhos de importação dentro dos meus arquivos .ts mesmo quando a importação está se referindo a um arquivo .ts ou .tsx. Não sei por que o compilador TypeScript aceita isso, mas pelo menos a saída da compilação inclui a extensão .js. Solução terrivelmente hacky embora.

Não é estranho e definitivamente não é hacky, e funciona perfeitamente com a resolução do navegador e do módulo nativo do Node.

O recurso que você está importando _é_ o arquivo .js. O tipo pode estar em um arquivo .ts ou em um arquivo .d.ts. Um arquivo .d.ts nem precisa ser um irmão do módulo .js, e não precisa haver uma relação de 1 para 1 entre arquivos .d.ts e arquivos .js.

Importar o módulo .js é a opção mais confiável e estável que o tsc poderia ter escolhido. Caso contrário, haveria casos em que você importaria os tipos e o tsc não saberia a maneira correta de reescrevê-los em um caminho de módulo real.

@justinfagnani Ah, acho que faz sentido. Eu não quis sugerir que qualquer coisa que o TypeScript estivesse fazendo aqui fosse hacky (não estou em posição de fazer uma afirmação como essa), apenas que senti que o que estava fazendo pode não ser típico. Eu acho que eu estava pensando sobre isso da maneira errada embora. Não é o TypeScript que importa o módulo, é o que avalia a saída da compilação (ou estou entendendo mal)? Nesse caso, posso ver por que funcionaria dessa maneira.

O recurso que você está importando _é_ o arquivo .js

Você está se referindo ao módulo construído aqui certo? Não é um arquivo .js no diretório de origem, mas a versão construída do módulo .ts?

Não poderia ser que, se você especificar explicitamente a extensão .ts ou .tsx em um caminho de módulo, a saída substituirá .js?

Acho que pode haver um mal-entendido sobre o que está acontecendo @kj. Quando você especifica uma extensão .ts sem ter compilado seu código, está referenciando o arquivo ts. Mas quando você compila usando tsc, ele converte o conteúdo do arquivo ts em um arquivo js que é executável no ambiente em que você está (nó ou navegador).

Eu entendo que @mkay581 , mas digamos que tenho esta linha em um arquivo foo.ts:

import { Component } from './Component.js';

O 'Component.js' ao qual estou me referindo é de fato 'Component.tsx' no sistema de arquivos (não há arquivo .js, a menos que o TypeScript esteja entendendo que isso se refere à eventual versão transpilada do arquivo?), ainda O TypeScript aceita isso perfeitamente e a mesma linha de importação está presente na saída (com a extensão .js que funciona com o Node ou o navegador).

A maneira tradicional do TypeScript (AFAIK) seria especificar essa linha de importação sem a extensão, como:

import { Component } from './Component';

Isso obviamente compila bem também, exceto que a linha de importação no arquivo .js transpilado não inclui a extensão .js em './Component', que é exigida por certos ambientes (e possivelmente soa como a especificação, embora eu não tenha leia para ter certeza).

Por outro lado, se eu especificar a linha com o nome do arquivo real do arquivo de origem:

import { Component } from './Component.tsx';

Então o TypeScript não reconhece o caminho e sugere que eu deveria tentar a linha de importação sem a extensão do arquivo (se bem me lembro, não estou no meu computador agora).

Então, o primeiro exemplo parece um pouco estranho para mim, pois estou escrevendo TypeScript, espero poder importar com a extensão .ts ou .tsx, mas ele só aceita o caminho sem extensão (o que parece ser em desacordo com outras implementações do sistema de módulos ES) ou com a extensão .js que só poderia se referir ao arquivo de saída, pois não tenho esse arquivo de origem.

@justinfagnani

O recurso que você está importando _é_ o arquivo .js.

Eu não sei como o tsc funciona, mas isso não me parece certo. Quando você escreve seu código, ainda não há arquivo .js. É trabalho do compilador criá-lo.

O TS atua como uma camada de abstração sobre o JS e os arquivos .js são a saída da etapa de compilação. Contar com eles estando lá com essa extensão específica parece quebrar a abstração, IMO.

Dito de outra forma, quando você está usando C ou C++ você não #include os arquivos .o em seu código, você inclui o .h ou no máximo o .c ou .cpp .

Estou disposto a aceitar uma explicação razoável para esse comportamento no Typescript, mas, a menos que esteja faltando alguma coisa, esta não parece ser isso.

@kj

Não é estranho e definitivamente não é hacky

Discordo duro. Para mim, é a própria definição de estranho e hacky. 😛 O que você está fazendo aqui é referenciar um arquivo hipotético. Um arquivo cuja existência não é garantida. (Por exemplo, ao agrupar código, usando AssemblyScript ou deno) Você está assumindo o formato de saída. Mas ao escrever código agnóstico (por exemplo, módulos de terceiros), isso é uma coisa _perigosa_ de se supor.

@borfast @frzi Sim, é basicamente assim que me sinto sobre isso, e fico feliz em ver que não sou o único que não se sente confortável com isso. Estou apenas tentando não fazer muitas suposições sendo tão novo no TypeScript!

@frzi

O que você está fazendo aqui é referenciar um arquivo hipotético. Um arquivo cuja existência não é garantida

Não hipotético, tsc sabe que vai gerá-lo. É garantido que existe, ao usar tsc.

Outra maneira de ver isso é que, se você importar o arquivo .ts, estará importando um arquivo que não estará lá após a compilação.

ao agrupar o código

Bundlers são executados após tsc

@kj mencionou arquivos .tsx, e eles levam meu ponto de vista ainda mais. .tsx existe apenas para sinalizar ao compilador desse módulo, _locally_, que o módulo contém JSX. Os importadores do módulo não precisam saber que havia JSX no arquivo e não podem saber após a compilação. Os arquivos podem ser facilmente portados entre os pares .tsx, .ts e .js/.d.ts.

Digamos que você esteja importando um arquivo .ts:

import {Component} from './component.ts';

E você quer usar JSX para o componente, então você o renomeia para component.tsx. Todas as importações devem falhar? Digamos que você migre de .ts para .js/.d.ts. As importações devem falhar novamente?

@borfast

O TS atua como uma camada de abstração sobre o JS e os arquivos .js são a saída da etapa de compilação. Contar com eles estando lá com essa extensão específica parece quebrar a abstração, IMO.

A abstração não é tão completa quanto você sugere aqui. Você pode importar arquivos .js de dentro ou de fora do seu projeto TS. Você pode adicionar tipos a um arquivo .js com um arquivo .d.ts que resida em qualquer lugar em seu projeto. Os arquivos .js são o que é real após a compilação. Todo o resto apenas ajuda o compilador.

@justinfagnani Estou ficando um pouco perdido com o que você está dizendo, mas por que o TypeScript não pode simplesmente assumir que, se você fornecer um caminho de importação com .ts ou .tsx, ele gerará um arquivo .js para esse módulo e portanto, deve substituir a última extensão na saída?

@justinfagnani

Não é hipotético, tsc _sabe_ vai gerá-lo. É garantido que existe, ao usar tsc.

Mas há uma simetria implícita aqui que você não está admitindo.

Essa “garantia” que você mencionou vale para os dois lados. Se, como você diz, “tsc _knows_ vai gerar [arquivos js]”, então é uma pergunta igualmente válida para perguntar: “Bem, então por que tsc NÃO está agindo nesta garantia e aplica as extensões .js que ele _knows_ é está faltando no js compilado?”

Interpretar o fato de que “tsc garante arquivos js” vai nos dois sentidos.

Então eu concordo, @justinfagnani , sua interpretação _é_ válida, de um certo ponto de vista. Mas a interpretação oposta é que “tsc deve, portanto, _agir de acordo com seu conhecimento_ e realizar esse processo para o desenvolvedor”. E o que me incomoda em todo esse debate desde o início é como essa interpretação é recebida _negativamente, quase ao ponto de ser ridicularizada. É irracional.

No final das contas, este debate é sobre _uma decisão estética, não lógica_. E minha esperança é que um tom de voz ampliativo e acomodatício – como é próprio da _opinião_ estética (não dedução lógica) – seja trazido a esse problema por seus detratores.

Em suma, por favor, admita que a pergunta do OP é uma interpretação perfeitamente válida – talvez junto com a sua. Não há necessidade de discussão dura.

Obrigado

@justinfagnani

Outra maneira de ver isso é que, se você importar o arquivo .ts, estará importando um arquivo que não estará lá após a compilação.

Claro que não, assim como um arquivo .h não é distribuído com o executável de um programa C. Esse é exatamente o ponto: você diz a um compilador para incluir arquivos de origem , não arquivos compilados .

Ok, eu recebo muito spam com essa conversa para ignorá-la ainda mais.
A instrução import NÃO faz parte do typescript, é parte do ambiente JavaScript que a executou. Agora, a palavra-chave aqui é ambiente JavaScript , pois ESTE é o que resolve os caminhos. Mostre-me um único aplicativo que em tempo de execução importa e executa arquivos .ts (claro, pode haver alguns, mas eles são o que eu chamaria de hacky).
O TypeScript permite adicionar extensões .js porque permite JavaScript nativo dentro de seus arquivos de origem. nenhum dos navegadores do node.js irá executar o arquivo .ts, mesmo ts-node transpila arquivos .ts em tempo real, apenas mantém o resultado na memória em vez de gravá-los no disco rígido (não é nada hacky certo ?).

Agora, a correção tsc adequada seria:

  • temos .ts arquivo
  • nós o referenciamos em outro arquivo
  • tsc transpila esse arquivo .ts para o arquivo .js
  • tsc então reescreve todas as referências diretas ao arquivo .ts com o arquivo .js (ele sabe exatamente como foi transpilado para poder atualizá-lo corretamente)

Problema: "modern web dev" não é um web dev real e usa a maneira node.js de importação, ignorando a extensão (e todo o caminho do arquivo). tsc agora não sabe mais qual será a saída, porque importar my-awesome-module/test pode ser qualquer coisa, começando de um arquivo test.js em node-modules/my-awesome-module , até index.js file dentro da pasta test em node-modules/my-awesome-module , terminando em algumas reescritas locais com arquivos não-js como ./local-mocks/my-awesome-module/mock.json .

É aqui que surge o problema: como um tsc pode saber qual é a configuração funky do webpack/rollup/super-awesome-new-and-shiny-bundler para seu projeto específico?

Novamente: eu sou a favor do tsc para reescrever os caminhos de importação, mas isso funcionaria apenas para projetos simples, e fazê-lo funcionar apenas para projetos simples (o que hoje em dia é uma minoria, pois mesmo páginas de apresentação simples usam reagir com configuração de webpack com engenharia excessiva) não vale a pena gastar tempo, se isso puder ser feito com um script simples e personalizado.

Novamente: eu sou a favor do tsc para reescrever os caminhos de importação, mas isso funcionaria apenas para projetos simples, e fazê-lo funcionar apenas para projetos simples (o que hoje em dia é uma minoria, pois mesmo páginas de apresentação simples usam reagir com configuração de webpack com engenharia excessiva) não vale a pena gastar tempo, se isso puder ser feito com um script simples e personalizado.

Como você faria isso em um projeto simples sem webpack, apenas com tsc quero dizer?

Estou lendo os comentários de todos e parece ser um desacordo fundamental das expectativas de uso datilografado aqui.

Quando os arquivos de origem .ts fazem referência a arquivos .js, o problema já começou.

Typescript foi construído para ~run~ compilar arquivos .ts de origem -- não arquivos .js. Se um desenvolvedor quiser usar TypeScript em seu projeto, ele deve converter seu projeto _inteiro_ para typescript e não deixar arquivos .js órfãos e tentar fazer referência a eles. E se você não tiver tempo para alterar o conteúdo dos arquivos js para a sintaxe Typescript, apenas renomeie os arquivos js para arquivos ts (ou use o mapeamento de caminho do TS para mapear importações para arquivos .js). Problema resolvido. :man_shrugging:

EDIT: Corrigido "executar" para "compilar", que é o que eu quis dizer, mas posso ver como isso pode ter sido interpretado de maneira diferente.

@ mkay581 O TypeScript nunca teve a intenção de executar nada, apenas para gerar arquivos JS.

@valeriob Projeto simples provavelmente teria alguns arquivos no máximo, o que não precisa ser empacotado. Os navegadores hoje em dia têm importações embutidas, não há necessidade de contornar isso. Então seria tão simples quanto ouvir os eventos de navegação no navegador e mapear cada evento para a rota correspondente, cada rota poderia importar dados com fetch e uma vez retornada poderia ser renderizada com mecanismos de modelagem não compilados (lit- html, HyperHTML, ou mais antigos como Bigode, Guiador, Pug etc). Pronto, não há necessidade de fantasiar webpack, framework ou qualquer biblioteca de utilitários, apenas ouvintes, regexp, fetch, promessas e um mecanismo de modelagem js simples.

Obrigado @Draccoz , então você pode me dizer como fazer esse cenário simples funcionar? https://github.com/valeriob/Typescript_Non_SPA
É um arquivo .ts simples referenciando uma biblioteca JS (rxjs como exemplo) e quero consumi-lo como módulo em uma página html.

@valeriob Isso não é tão trivial quanto deveria ser. A maioria das bibliotecas de terceiros, mesmo quando declaram que são compatíveis com ES Modules, não estão no mundo dos navegadores.
O RxJS é algo em que eu estava mais interessado ao trazê-lo para o fluxo nativo, mas eles esperam que esse ticket seja resolvido antes de decidir implementá-lo (engraçado...).
Na arquitetura que eu estava projetando, inicialmente usei sed para corrigir todas as importações, mas depois mudei de ideia para usar um servidor de desenvolvimento simples com reescrita de caminho. Meu conceito é não ter dependências externas em meus aplicativos além de rxjs, typescript e lit-html (node_modules com 4 pastas e testes/compilações de CI ULTRA rápidos). Se o TS reescrevesse os caminhos, eliminaria a necessidade do meu servidor, embora tenha cerca de 90 linhas de código de qualquer maneira. É open source, se alguém quiser um link é só pedir ou verificar as organizações no meu perfil.

Quanto às páginas simples, eu estava me referindo àquelas que realmente não precisam de nenhuma biblioteca, como acessar uma url -> buscar dados -> exibi-los -> repetir.

Não precisar usar nenhuma biblioteca em Js é pura fantasia, já que Js não possui biblioteca base.

O cenário simples é o que eu vinculei e não está funcionando. Também é o cenário mais comum para pessoas que não querem mergulhar no mundo louco de webpack/compilação que complica as coisas sem nenhum benefício real, limita muito suas opções, faz os devs lutarem mais contra as ferramentas do que escrever seu aplicativo e retardar seu dev ciclo.

Muitas ginásticas mentais estão acontecendo aqui para negar que esse problema exista e que seja uma preocupação importante para a produtividade de muitos desenvolvedores.

Explicar que _não deveria ser um problema_ não _resolve o problema_. O software deve estar de acordo com os modelos mentais dos usuários, não impor seu próprio modelo de implementação aos usuários. (coisas de UX)

Se os usuários estão conceituando tsc como um compilador semelhante a C, conforme @borfast , então esse é o modo mental privilegiado que precisa ser acomodado, apesar dos detalhes de implementação do tsc.

A pergunta do OP tem mais de 200 polegares para cima, mais do que todos os outros problemas no repositório.

Esta questão merece um voto da comunidade. Por favor, considere iniciar uma enquete.

Se a maioria dos usuários deseja que o tsc reescreva suas importações, essa é a resposta certa. Pelo menos essa é a maneira UX de ver as coisas.

É ainda mais simples do que isso, se o typescript como linguagem é um superconjunto de JavaScript, a saída de tsc (mesmo o switch de arquivo de saída não único) deve ser digerível pelo próprio JavaScript.

@weoreference se você definir de maneira clara (não escrever código, apenas projetar) como EXATAMENTE deve reescrever caminhos, considerando vários ambientes (node.js, navegador), várias possibilidades de configurações de bundler (investigando todos os recursos atuais, planejados e possíveis futuros de webpack, rollup and parcel e quaisquer outros bundlers) então com certeza, então acredito que a equipe do TypeScript estaria completa do seu lado.

Se você não está disposto a fazer isso ou acha que é muito difícil, pare de pedir para eles criarem um recurso que ninguém pode realmente descrever, é como "eu não me importo como, mas faça essa vaca voar"...

@Draccoz , você quer que seu carro mude de marcha para poder dirigi-lo a mais de 10 km / h, mas tenho certeza de que você nunca foi solicitado pelo fabricante para aprender como funciona um trem de engrenagens, muito menos projetar um.

Quanto à questão dos bundlers e outros enfeites, por que isso é um bloqueador para isso?

Olha, eu só quero usar módulos ES, não quero lidar com toda a insanidade de Babel e Webpack. Por que isso não pode ser uma opção opcional do compilador que simplesmente altera a extensão do arquivo para .js? Se este comportamento entrar em conflito com outras opções de configuração definidas pelo usuário, ele deve ser desabilitado automaticamente, ou um aviso/erro deve ser mostrado e a compilação interrompida quando o tsc é executado, para que o usuário saiba que precisa alterar a configuração.

Eu realmente não vejo porque isso é impossível.

@Draccoz Olá :) Bem, a meu ver, você está perguntando duas coisas:

  1. Como pode ser implementado

  2. Como eu, o desenvolvedor, posso sinalizar ao tsc que quero que as importações sejam renomeadas de uma determinada maneira, para o meu ambiente específico

Aqui estão meus pensamentos.

  1. Por favor, veja a resposta de @borfast ; é uma resposta de “ordem superior”, mas sucinta :)

  2. Talvez eu possa passar um sinalizador para tsc/tsconfig, como “renameImports”:true, ou algum outro sinal que seja captado pelo tsc. Se for necessária mais precisão, talvez o sinalizador não deva ser booleano, mas sim uma string, talvez algo assim:

standardImportExtension: 'js'

portanto, todas as importações sem extensões de arquivo são padronizadas para .js

Conclusão:
Esta funcionalidade só parece difícil de implementar porque você assume que Q2 (esquema de renomeação de importação) precisa ser conhecido antecipadamente por Q1 (ou seja, por tsc). Mas, na verdade, não. Eu, o desenvolvedor humano, posso facilmente fornecer esse “conhecimento do mundo” para o tsc sem que ele precise saber como funciona o webpack/browsers/etc. Tudo isso com uma simples bandeira.

@borfast Transmission não foi solicitado por um usuário, foi fornecido com um carro por um fabricante, o usuário apenas concordou que é um novo recurso e começou a usá-lo - desculpe, este não é um argumento adequado. Comparado ao seu exemplo de usuário - fabricante de automóveis, é mais como "Eu quero que meu carro seja um carro elétrico completo com alcance de 100 mil milhas e velocidade máxima atingindo a velocidade de um jato. Não me importo como alcançá-lo, eu quero e é isso - período.
@weoreference pouco mal-entendido nas minhas perguntas. Eu estava perguntando sobre: ​​como fazer o tsc entender para o que o caminho aponta? É um arquivo js diretamente? Ou é uma pasta com index.ts dentro? Ou é um módulo com package.json que contém o campo main ? Ou esnext campo? Ou qualquer outro que não seja padrão? Ou é um caminho que é reescrito pelo webpack? Ou enrolação? Se sim, onde está a configuração? É outro bundler talvez? Alguns menos conhecidos? E quais são os outros casos de uso que eu não pensei na frase acima?

Talvez eu possa passar um sinalizador para tsc/tsconfig, como “renameImports”:true, ou algum outro sinal que seja captado pelo tsc.

@weoreference você já não pode fazer isso com mapeamento de caminho ? A opção paths no arquivo TSconfig nos dá o controle para mapear os caminhos de importação para arquivos JS. Desculpe se estou interpretando errado.

@Draccoz Obrigado pela sua resposta, por favor, deixe-me esclarecer

E quais são os outros casos de uso que eu não pensei na frase acima?

Ah, sim, seria muito difícil para o tsc ter conhecimento sobre todas essas combinações de ferramentas de ambiente/construção.

Mas o tsc pode ter um utilitário simples que ajuda os desenvolvedores a cobrir a maioria dos casos de uso, e esse é o valor de configuração “standardImportExtension” que expliquei.

Claro, aqui vem o problema da “garantia”. Anteriormente neste tópico, foi argumentado que o tsc deveria “garantir” que o js compilado de fato rodaria [em algum ambiente].

Bem... talvez fosse um compromisso muito difícil. É, de fato, muito difícil para o tsc garantir que o js será executado [em algum ambiente], porque, como você acabou de descrever, esse ambiente é muito difícil de definir no cenário js atual.

Mas o utilitário de sinalizador simples proposto por @borfast resolve _a maioria_ dos erros de importação js encontrados por novos usuários tentando tsc.

Uso avançado, que, como você mencionou, consiste em todas essas considerações -

É um arquivo js diretamente? Ou é uma pasta com index.ts dentro? Ou é um módulo com package.json que contém o campo principal? Ou esnext campo? Ou qualquer outro que não seja padrão? Ou é um caminho que é reescrito pelo webpack? Ou enrolação? Se sim, onde está a configuração? É outro bundler talvez?

- bem, esse uso pode de fato ser deixado para scripts de usuário personalizados, bundlers e outras ferramentas.

Mas só porque o uso avançado é difícil de resolver não significa que devemos evitar resolver os casos fáceis.

E o caso mais fácil é adicionar uma extensão .js às importações; que podemos resolver, e devemos resolver.

@weoreference , então sou votado por você por fazer uma pergunta e tentar ser útil e, em seguida, você ignora a pergunta. Parece que você só quer discutir e debater em vez de realmente progredir para uma solução produtiva. Você rejeitou a tentativa de todos de fazê-lo. Última mensagem para mim neste tópico. Peço desculpas por todo o spam, pessoal.

@weoreference veja bem no início desta conversa, nos comentários de @DanielRosenwasser . Ele explica por que eles não iriam implementá-lo ("no momento"? dando esperança inútil). Depois de sua declaração ninguém datilografado comentou mais sobre o assunto. Para mim, essa discussão deve ser encerrada e a Microsoft deve declarar oficialmente sua posição. Período.
Apenas como uma nota lateral - pessoalmente, sou a favor desse recurso, simplificaria MUITO. Perdi minha esperança, pois também entendo os argumentos da equipe datilografada.

@weoreference

Não hipotético, tsc sabe que vai gerá-lo. É garantido que existe, ao usar tsc.

Mas há uma simetria implícita aqui que você não está admitindo.

Essa “garantia” que você mencionou vale para os dois lados. Se, como você diz, “tsc sabe que vai gerar [arquivos js]”, então é uma pergunta igualmente válida: “Bem, então por que tsc NÃO está agindo nesta garantia e aplica as extensões .js que ele sabe que são está faltando no js compilado?”

A simetria não se sustenta na verdade. Não é tão simples como apenas "aplicar uma extensão .js" - tsc teria que resolver e reescrever o especificador, e a resolução pode depender de declarações de tipo. TypeScript e Babel suportam modos de compilação de módulo único (isolatedModules para tsc) e, neste caso, se você importar tipos em vez de JavaScript, tsc teria que carregar as declarações de tipo para determinar onde o arquivo .js correspondente estaria, para reescrever o especificador. Para manter as coisas consistentes e não ter casos extremos, é mais simples oferecer suporte apenas à importação dos arquivos .js que existem antes da compilação ou são um resultado conhecido do projeto atual.

@justinfagnani @Draccoz Obrigado; tudo bem, sim eu entendo.

Meu comentário final: "só porque os casos difíceis não podem ser resolvidos não significa que não podemos resolver os casos fáceis."

Obrigado

Estive sob a suposição de que o TypeScript está indo contra a especificação aqui (e produzindo JavaScript inválido), mas não consigo encontrar em nenhum lugar na especificação que realmente exija que o caminho de importação corresponda exatamente aos nomes dos arquivos (com extensão). É muito difícil de digerir, então não estou completamente confiante, mas tudo o que posso encontrar é que a especificação exige que o 'ModuleSpecifier' na 'FromClause' seja um 'StringLiteral'. Parece uma definição muito vaga, mas suponho que pode ser para permitir flexibilidade na resolução do módulo nos muitos ambientes diferentes em que o ECMAScript existe. Alguém pode confirmar se estou lendo isso corretamente? Se esse for realmente o caso, eu teria que suavizar minha posição em relação à maneira como o TypeScript lida com isso. Embora eu ainda prefira que haja mais interoperabilidade entre TypeScript, Node e a web. A situação atual não é ideal.

Cheguei a esse problema depois de ler isso . Esse problema me deu a impressão de que o sistema do Node funciona da maneira que funciona (nomes de arquivos estritamente correspondentes) devido à especificação do ES, mas posso ver agora que li isso (eles não estavam se referindo à especificação do ES) e talvez nem o Node, nem o TypeScript estão realmente fazendo algo 'errado'. Então, esse problema é realmente sobre incompatibilidades entre abordagens igualmente válidas para resolução de módulos entre diferentes ambientes. Ainda assim, claramente os principais ambientes de destino do TypeScript são o Node e a Web, e embora o Node possa teoricamente mudar sua abordagem, não acho muito provável que os navegadores o façam, então ainda acho que esse problema é válido.

Edit: Eu acho que pode ser esta seção da especificação que parece especificar que a resolução do módulo é 'definida pelo host'?

@kj o texto de especificação relevante está na especificação HTML: https://html.spec.whatwg.org/multipage/webappapis.html#resolve -a-module-specifier

Ele diz que os especificadores de importação devem ser URLs completos ou caminhos absolutos ou relativos. Se o especificador não analisar como um URL (geralmente começando em http:// ou https:// ) ou começar com / , ./ ou ../ , um erro é lançado. Os especificadores de caminho são resolvidos em relação à URL base dos importadores.

Nenhuma outra busca ou resolução de caminho é feita. Isso significa que o especificador deve resolver para a URL completa do módulo e você deve incluir a extensão se o servidor exigir. Os servidores têm a opção de retornar respostas para URLs sem extensão.

A razão pela qual o Node optou por um algoritmo de resolução mais restritivo para módulos é para ser mais compatível com a web, de modo que é mais comum que os módulos publicados no npm não precisem de ferramentas extras para serem executados nativamente nos navegadores. Importar por nome de pacote ainda é um recurso muito importante, então o Node suporta isso, mas visando ser compatível com a proposta de Import Maps (que Deno e SystemJS já suportam).

Ao todo, o suporte do tsc para importação com extensões .js funciona perfeitamente em navegadores Node e web. Na verdade, são as importações sem extensão que causam problemas sem ferramentas adicionais. Normalmente, porém, as ferramentas que suportam a resolução Node para nomes de pacotes também usarão a resolução de estilo de classe require() e resolverão caminhos relativos e adicionarão suas extensões também. Isto é o que es-dev-server faz.

Obrigado @justinfagnani. Então, pelo menos no navegador, depende apenas de como o servidor o implementa. Isso é bom saber. Isso ainda é pouco intuitivo e confuso e acredito que precisa haver mais convergência entre os projetos para o bem da comunidade, mas não tenho mais certeza de como isso pode ser.

Edit: Por enquanto, isso será suficiente para mim (especialmente dadas as explicações acima, me sinto mais confortável com isso):

https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm

Não tenho certeza se essa opção é referenciada na documentação do TypeScript, mas se não for, talvez deva ser para evitar confusão. Não parece ser, procurando por ' site:typescriptlang.org specifier-resolution' ou ' site:staging-typescript.org specifier-resolution'. Embora, como isso ainda é muito novo no Node, isso não é muito surpreendente.

@justinfagnani Concordo que a extensão .js funciona na maioria dos casos, exceto nos casos em que alguém assume uma postura ideológica _contra_ ela (por exemplo, https://github.com/TypeStrong/ts-node/issues/783, que você conhece).

Eu fiz uma versão sem dependência do script @quantuminformation aqui . Essa versão também contém um regex que substituirá apenas os módulos que já não terminam com .js .

mesma necessidade

Alcançar extensões .js para compatibilidade com ESM usando .js nas instruções de importação não está funcionando para mim. Quando importo um arquivo TS e omito qualquer extensão, ele compila bem. Quando adiciono uma extensão .js à importação, recebo muitos erros (que não deveriam existir) do compilador TS.

Parece que a principal razão pela qual este recurso não está sendo desenvolvido é devido à dificuldade/impossibilidade de compatibilidade com vários bundlers, mas Node.js e bundlers desenvolveram seus próprios esquemas de módulos na ausência de suporte para módulos em ECMAScript. Agora que temos o ESM, por mais inadequado que algumas pessoas possam considerá-lo, é o caminho a seguir. À medida que mais código é desenvolvido no ESM e nos componentes da Web, o uso de bundlers diminuirá e esse ponto problemático entre o TS e o ESM desenvolverá mais atrito. Seria bom, mesmo que o suporte inicial fosse bugado e não considerasse todos os casos de uso, se pudesse começar a ser suportado.

Até que haja uma solução melhor, este é um script de nó sem dependências para usar como tarefa de compilação

configure em seu package.json:

  ..
    "scripts": {
        "build": "node build.js",
   ...

//build.js
import { execSync} from "child_process"
import * as util from "util"
import * as fs from "fs"
import * as path from "path"

//function to recurse dirs finding files
function fromDir(startPath, filter, callback) {

    //console.log('Starting from dir '+startPath+'/');

    if (!fs.existsSync(startPath)) {
        console.log("no dir ", startPath);
        return;
    }

    var files = fs.readdirSync(startPath);
    for (var i = 0; i < files.length; i++) {
        var filename = path.join(startPath, files[i]);
        var stat = fs.lstatSync(filename);
        if (stat.isDirectory()) {
            fromDir(filename, filter, callback); //recurse
        }
        else if (filter.test(filename)) callback(filename);
    };
};

//this add .js to lines like:  import .* from "\.  <-- only imports from ./ or ../ are touched
function addDotJsToLocalImports(filename) {
    var buf = fs.readFileSync(filename);
    let replaced = buf.toString().replace(/(import .* from\s+['"])(?!.*\.js['"])(\..*?)(?=['"])/g, '$1$2.js')
    if (replaced !== buf.toString()) {
        fs.writeFileSync(filename, replaced)
        console.log("fixed imports at "+filename )
    }
}

//------------------------
//---BUILD TASK START 
//------------------------

execSync("npx tsc --build -verbose", { stdio: 'inherit' })

//add .js to generated imports so tsconfig.json module:"ES2020" works with node
//see: https://github.com/microsoft/TypeScript/issues/16577
fromDir("./dist", /\.js$/, addDotJsToLocalImports)

baseado em https://github.com/microsoft/TypeScript/issues/16577#issuecomment -310426634

Alguém pode se lembrar do que eles estavam fazendo 3 anos atrás quando esta edição foi aberta?

A solução não empacotadora é escrever projetos distribuídos na web com .js como extensão.

Isso 100% funciona. O maior problema é tentar escrever módulos direcionados à web e Node.js, mas isso é um problema para JS em geral.

Se houvesse algo a ser feito, seria adicionar --moduleResolution=web , mas esse não é o escopo deste problema aqui.

Eu tive que escrever este script de pós-compilação para adicionar a extensão .js.

fix-ts-imports

#!/usr/bin/env sh

# Fixes JavaScript module imports generated by TypeScript without extension.
# Converts
# import {} from './module'
# into
# import {} from './module.js'
#
# EXAMPLE
# ./fix-ts-imports

ProjectDir="$(cd "$(dirname "$0")/.." && pwd)"

fix() {(
        local pkg="$1"
        shift

        find "$pkg" -type f -iname '*.js' -not -ipath '*/node_modules/*' -print0 \
        | while read -r -d '' file; do
                sed -i '' -E 's|(import .+ from ['\''"]\.?\./.+[^.][^j][^s])(['\''"])|\1.js\2|g' "$file"
        done
)}

if test $# -eq 0; then
        set -- "$ProjectDir"
fi

for pkg; do
        fix "$pkg"
done

Eu tenho um script semelhante, em JavaScript:
https://github.com/yoursunny/NDNts/blob/743644226fe18d48e599181e87ad571a2708a773/mk/build-post.js

É invocado como:

tsc -b mk/tsconfig-solution.json -w --listEmittedFiles \
  | node mk/build-post.js

A principal desvantagem desse tipo de script é que eles quebram os mapas de origem, de modo que a depuração se torna menos eficaz.

usando ferramentas modernas e extensões .js na fonte, tudo funciona perfeitamente no nó e nos navegadores

  • texto datilografado
  • es módulos
  • rolar

Só posso supor que as pessoas com problemas aqui estão realmente presas em algum híbrido quebrado de módulos es e resolução de nós, já que os desenvolvedores se apegam a marcos familiares de seus fluxos de trabalho antigos - provavelmente o webpack é o culpado ...

— provavelmente o webpack é o culpado...

E assim - o gato está fora do saco.

usando ferramentas modernas e extensões .js na fonte, tudo funciona perfeitamente no nó e nos navegadores

_A maioria_ das coisas funciona de maneira excelente, e eu concordo que todos os arquivos de origem devem ter extensões .js em suas exportações. Na minha experiência, a única coisa que não funciona bem com isso é o ts-node, devido à sua recusa teimosa em oferecer suporte a extensões .js . Sim, você pode adicionar uma etapa de pré-transpilação antes de executar o node, e as importações .js funcionarão, mas se você quiser executar o código .ts ou testar diretamente com o node e também no navegador, você está atualmente sem sorte. (Para esclarecer, acho que este é um bug do ts-node, não um bug do TypeScript).

Obrigado @chase-moskal.

Eu refatorei o repositório e o arquivo tsconfig, e agora
import {something} from './something.js'
não joga
typescript force overwrite error TS5055: Cannot write file because it would overwrite input file
mais, e eu não preciso mais do hack fix-ts-imports .

Em mais de 250 comentários, houve muito pouca clareza. Para resumir:

Fundo

Módulos do navegador

Os navegadores resolvem os módulos EcmaScript de acordo com o URL, incluindo URLs relativos. ( whatwg )

Módulos Node.js

O Node.js resolve módulos (tanto o EcmaScript quanto o CommonJS específico do Node.js) por meio de um algoritmo muito mais complexo que envolve vários fallbacks e análise de arquivos package.json. ( Node.js ) Isso pode ser personalizado, por exemplo, com --experimental-specifier-resolution=explicit que requer caminho completo.

Módulos TypeScript

O TypeScript possui vários algoritmos de resolução de módulo disponíveis e uma variedade de opções para personalizá-los ainda mais. ( TypeScript ) A intenção é que os usuários escrevam os mesmos especificadores de módulo usados ​​na saída produzida, ajustando a resolução do tsc com opções como baseUrl e pathMappings.

Na prática, a maioria dos usuários usa o node moduleResolution, visando um ambiente Node.js ou bundler compatível. Essa solicitação se concentra em usuários que segmentam navegadores sem um empacotador.

resolução do módulo ts-node

Aparentemente, o ts-node não suporta identificadores de módulo com extensões. Embora não esteja claro o porquê, já que tanto o Node.js quanto o TypeScript o fazem, e o ts-node é ostensivamente a amálgama deles.

Fatos

Fato 1: você pode usar extensões .js

Para maior compatibilidade (ou seja, navegadores), você pode usar extensões .js hoje. Com a estranha exceção do ts-node (bug IMO), tudo funciona agora especificando o caminho completo (ou seja, incluindo a extensão).

Fato 2: Não é tão simples quanto "adicionar extensão"

Essa solicitação é melhor resumida como "transforme o identificador do módulo para o caminho do arquivo". Por exemplo ./example torna-se ./example/index.js e 'lodash' torna-se '.node_modules/lodash/index.js' .

Observe que às vezes não há nem mesmo um caminho de arquivo resolvido, como nas declarações do módulo ambiente.

declare module "lodash" {
}

Talvez a reescrita do módulo esteja limitada aos módulos TS no projeto/compilação atual.

De qualquer forma, estamos violando um dos parâmetros de projeto do TS, que outros módulos afetam a saída do atual.

Conclusão

É possível usar o caminho para identificadores de módulo que funcionam para web. (Por exemplo ./foo/index.js em vez de ./foo .)

(Embora praticamente falando, você provavelmente desejará um empacotador de qualquer maneira para navegadores de destino. Ou seja, se os pacotes npm forem usados.)

@pauldraper há um problema importante com o "Fato 2":

Essa solicitação é melhor resumida como "transforme o identificador do módulo para o caminho do arquivo". Por exemplo, ./example se torna ./example/index.js e 'lodash' se torna 'node_modules/lodash/index.js'.

Você realmente não quer resolver especificadores fora do seu pacote em tempo de compilação, porque estes podem não ser os caminhos disponíveis quando o pacote é instalado em outro lugar. Você precisa executar a resolução do módulo Node em cada instalação de pacote exclusivo. Caso contrário, poderíamos escrever e publicar import {} from './node_modules/lodash/index.js' e terminar com isso.

@justinfagnani , concordo, mas isso demonstra que os identificadores de módulo são abstratos e você está manipulando locais de módulos fora do tsc. E esse tsc não pode/não precisa se preocupar com tais manipulações.

Essa solicitação é melhor resumida como "transforme o identificador do módulo para o caminho do arquivo". Por exemplo, ./example se torna ./example/index.js e 'lodash' se torna '.node_modules/lodash/index.js'.
Observe que às vezes não há nem mesmo um caminho de arquivo resolvido, como nas declarações do módulo ambiente.

Não é disso que se trata este pedido. Trata-se de adicionar extensão ao emitir código. Queremos escrever módulos compatíveis com o tipo: "module" sem etapa adicional de compilação hacky. Módulos externos como lodash continuariam a funcionar mesmo sem .js, pois são CommonJs.

Exemplo:

// ./src/moduleA.ts
export const test = 2;
// ./src/moduleB.ts
import {test} from './moduleA'



md5-ec0300a1c6d92a03c70699d0e52c0072



```js
// ./lib/moduleB.js
import {test} from './moduleA.js'

Além do texto datilografado acima, não há suporte para package.json "exports" e "type". Não há caminho para o verdadeiro ESM nos projetos que gerencio.

Essa solicitação se concentra em usuários que segmentam navegadores sem um empacotador.

Isso é incorreto. Raramente escrevo TS/JS para navegadores, trabalho principalmente no código do lado do servidor e também preciso disso porque quero usar o carregamento do ESM no nó e não depender de bundlers e código extra para carregamento de módulo.

Módulos externos como lodash continuariam a funcionar mesmo sem .js, pois são CommonJs.

A menos que não sejam.

Quando emitido.

Pode ser ./moduleA.js . Ou pode ser ./moduleA/index.js , certo? A resolução do módulo Node.js permite vários caminhos.

A menos que não sejam.

Você pode fornecer um exemplo de quando isso não funcionaria? O Node.js acaba de receber suporte para importar exportação nomeada do CommonJS.
https://nodejs.org/api/esm.html#esm_import_statements

Pode ser ./moduleA.js. Ou pode ser ./moduleA/index.js, certo? A resolução do módulo Node.js permite vários caminhos.

Não no modo ESM. index.js não seria mais compatível como é agora. O carregador do ESM leria os metadados do package.json "exports" e "type".
https://nodejs.org/api/esm.html#esm_mandatory_file_extensions

Para projetos baseados em typescript + node.js, precisamos de uma melhor história nativa do ESM. Isso pode acontecer via ferramental (typescript) ou no node.js O problema é que não há consenso sobre o que deve ser feito.

Edite o link removido para o PR do nó, pois era enganoso.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

blendsdk picture blendsdk  ·  3Comentários

Antony-Jones picture Antony-Jones  ·  3Comentários

fwanicka picture fwanicka  ·  3Comentários

siddjain picture siddjain  ·  3Comentários

DanielRosenwasser picture DanielRosenwasser  ·  3Comentários