Introdução
Os processos de construção no TypeScript podem se tornar bastante complexos quando temos que configurar nosso fluxo de projeto manualmente por meio do arquivo tsconfig.json
. Isso ocorre porque essas configurações exigem compreender o compilador TypeScript e o sistema de módulos .
Tendo trabalhado em muitos projetos TypeScript sozinho, consegui identificar dois problemas comuns que surgem ao usar módulos TypeScript e, mais importante, como resolvê-los de forma eficaz.
Pré-requisitos
Para obter o máximo deste artigo, você vai querer se preparar com o seguinte:
- Uma sólida experiência em JavaScript e TypeScript
- Uma sólida compreensão do sistema de módulos TypeScript
Problema 1: localização irregular das dependências
Em uma ocasião normal, o diretório node-modules
está geralmente localizado no diretório raiz (ou seja, baseUrl) do projeto, conforme mostrado abaixo:
projectRoot ├── node_modules ├── src │ ├── file1.ts │ └── file2.ts └── tsconfig.json └── package.json
Às vezes, no entanto, os módulos não estão localizados diretamente no baseUrl
. Por exemplo, dê uma olhada no seguinte código JavaScript:
//index.js importar expresso de"expresso";
Carregadores como webpack usam uma configuração de mapeamento para mapear o nome do módulo (neste caso, express
) para o arquivo index.js
em tempo de execução, traduzindo assim o trecho acima para node_modules/express/lib/express
em tempo de execução.
Neste ponto, quando usamos o snippet traduzido acima em um projeto TypeScript, devemos configurar o compilador TypeScript para lidar com a importação do módulo usando a propriedade "caminhos"
:
//tsconfig.json { "compilerOptions": { "baseUrl":"./src", "caminhos": { "express": ["node_modules/express/lib/express"] } } }
No entanto, com a configuração acima, o compilador TypeScript gerará o seguinte erro:
módulo expresso não encontrado
Aqui está o que está acontecendo nos bastidores: o compilador TypeScript procura node_modules
no diretório src
, embora node_modules
esteja localizado fora do diretório src
, determinando assim que o módulo não foi encontrado.
Solução 1: localize o diretório correto
O mapeamento em "caminhos"
é resolvido em relação a "baseUrl"
. Portanto, nossa configuração deve ser a seguinte:
//tsconfig.json { "compilerOptions": { "baseUrl":"./src",//Deve ser especificado se"caminhos"for. "caminhos": { "express": ["../node_modules/express/lib/express"]//Este mapeamento é relativo a"baseUrl" } } }
Quando usamos esta configuração, o compilador TypeScript “salta” um diretório do diretório src
e localiza o diretório node_modules
.
Como alternativa, a configuração abaixo também é válida:
//tsconfig.json { "compilerOptions": { "baseUrl":".",//Isso deve ser especificado se"caminhos"for. "caminhos": { "express": ["node_modules/express/lib/express"]//Este mapeamento é relativo a"baseUrl" } } }
Quando usamos esta configuração, o compilador TypeScript irá procurar o diretório node_modules
no diretório raiz do projeto.
Problema 2: vários locais de fallback
Nosso segundo problema comum também está relacionado à localização. Vamos considerar a seguinte configuração de projeto:
projectRoot ├── ver │ ├── file1.ts (importa'view/file2'e'nav/file3') │ └── file2.ts ├── componentes │ ├── rodapé │ └── nav │ └── file3.ts └── tsconfig.json
Aqui, o módulo view/file2
está localizado no diretório view e nav/file3
no diretório de componentes.
Resolver módulos em vários locais pode ser um pouco desafiador porque, neste ponto do código, o compilador não sabe como resolver esses módulos em locais diferentes. Na seção a seguir, revisaremos como resolver esse problema.
Solução 2: Localize o módulo e resolva as importações
Usando a configuração abaixo, podemos dizer ao compilador para procurar em dois locais (ou seja, ["*","components/*"]
) para qualquer importação de módulo no projeto:
{ "compilerOptions": { "baseUrl":".", "caminhos": { "*": ["*","componentes/*"] } } }
Neste exemplo, o valor "*"
na matriz significa o nome exato do módulo, enquanto o valor "components/*"
é o nome do módulo ( “Componentes) com um prefixo anexado.
Agora podemos instruir o compilador a resolver as duas importações da seguinte maneira:
import'view/file2'
O compilador irá então substituir 'view/file2'
pelo primeiro local na matriz ("*"
) e combiná-lo com o baseUrl
que resulta em projectRoot/view/file2.ts
. Isso permitirá que o módulo seja encontrado.
Após esta etapa, o compilador irá para a próxima importação:
import'nav/file3':
Da mesma forma, o compilador substituirá 'nav/file3'
pelo primeiro local na matriz ("*"
)-também conhecido como nav/file3
-e combine-o com o baseUrl
que resulta em projectRoot/nav/file3.ts
. Desta vez, o arquivo não existe, então o compilador substituirá 'nav/file3'
pelo segundo local "components/*"
e o combinará com o baseUrl
. Isso resultará em projectRoot/components/nav/file3.ts
, permitindo que o módulo seja encontrado.
Como o TypeScript resolve módulos por padrão
Sem configurar o compilador TypeScript conforme discutido anteriormente, o TypeScript adotará a estratégia de resolução de tempo de execução Node.js por padrão para localizar os módulos solicitados em tempo de compilação.
Para fazer isso, o compilador TypeScript procurará arquivos.ts,.d.ts,.tsx e arquivos package.json. Se o compilador encontrar um arquivo package.json, ele verificará se esse arquivo contém uma propriedade de tipos que aponta para um arquivo de digitação. Se nenhuma propriedade for encontrada, o compilador tentará procurar os arquivos de índice antes de passar para a próxima pasta.
Aqui está um exemplo. Uma declaração de importação como import {b} from'view/file2'
em /projectRoot/view/file1.ts
resultaria na tentativa dos seguintes locais para localizar ".view/file2"
:
- O
/projectRoot/view/file2.ts
existe? - O
/projectRoot/view/file2.tsx
existe? - O
/projectRoot/view/file2.d.ts
existe? - Existe
/projectRoot/view/file2/package.json
(se especifica uma propriedade"types"
)? - O
/projectRoot/view/file2/index.ts
existe? - O
/projectRoot/view/file2/index.tsx
existe? - O
/projectRoot/view/file2/index.d.ts
existe?
Se o módulo não for encontrado neste ponto, o mesmo processo será repetido, saltando uma etapa da pasta pai mais próxima da seguinte maneira:
- O
/projectRoot/file2.ts
existe? - O
/projectRoot/file2.tsx
existe? - O
/projectRoot/file2.d.ts
existe? - Existe
/projectRoot/file2/package.json
(se especifica uma propriedade"types"
)? - O
/projectRoot/file2/index.ts
existe? - O
/projectRoot/file2/index.tsx
existe? - O
/projectRoot/file2/index.d.ts
existe?
Conclusão
Às vezes, podemos nos deparar com algumas situações complexas em que diagnosticar porque um módulo não foi resolvido pode ser muito difícil. Em tais situações, habilitar o rastreamento da resolução do módulo do compilador usando tsc--traceResolution
pode fornecer mais informações sobre o que aconteceu durante o processo de resolução do módulo, permitindo-nos escolher a solução correta no futuro.
Com os problemas comuns dos módulos TypeScript destacados e as soluções fornecidas neste post, espero que seja um pouco mais fácil configurar o compilador TypeScript para manipular módulos em seus projetos TypeScript.
Esperamos que você tenha achado esta postagem informativa e útil. Você também pode verificar a documentação oficial do TypeScript para se aprofundar na resolução do módulo TypeScript.
A postagem Problemas comuns do módulo TypeScript e como resolvê-los apareceu primeiro no LogRocket Blog .