Problemas de compatibilidade e otimização de CI para considerar antes de migrar para o TypeScript 7
29 июля 2026 г.
0
Computing/SoftwareComments (0)
Log in to leave a comment
No posts yet
Log in to leave a comment
No posts yet
Foi lançado o TypeScript 7, reescrito do zero em Go. Com a notícia de que a velocidade de verificação de tipos ficou até 12 vezes mais rápida, as equipes que gerenciam grandes monorepos certamente vão querer fazer a transição o quanto antes. De fato, as equipes de engenharia da Vanta e do VS Code relataram ter reduzido o tempo de build das suas pipelines de CI em mais de 80%.
No entanto, aplicar a atualização sem o devido planejamento pode quebrar toda a sua CI. Isso ocorre porque a mudança para um binário nativo adiou o suporte às APIs de análise estática existentes para versões futuras. Ferramentas que inspecionavam APIs internas via require('typescript'), como @typescript-eslint e ts-morph, pararam de funcionar de uma vez. Embora o desempenho seja atraente, a quebra da cadeia de ferramentas é outro problema. Para evitar interrupções no deployment e ainda aproveitar o ganho de velocidade, são necessários alguns contornos.
O binário tsc do TypeScript 7.0 bloqueia completamente as chamadas a módulos internos do Node.js. Pacotes que antes eram importados e usados no ambiente JS passam a gerar erros imediatamente no momento do build. Subir a versão sem preparação pode paralisar toda a pipeline de CI.
É mais seguro colocar um script de diagnóstico no topo da pipeline. A ideia é varrer todos os arquivos package.json e tsconfig.json do workspace para identificar opções ou pacotes rejeitados pelo TS 7. Se restarem configurações de versões antigas, como ignoreDeprecations ou target: es5, o script lança um erro imediatamente e interrompe o processo.
`javascript
// scripts/check-ts7-compatibility.mjs
import fs from 'node:fs';
import { globSync } from 'glob';
const INCOMPATIBLE_DEPS = [
'ts-morph',
'ts-node',
'@babel/plugin-transform-typescript',
'typescript-eslint',
'@typescript-eslint/parser'
];
const DEPRECATED_TSCONFIG_OPTIONS = ['target:es5', 'moduleResolution:node', 'baseUrl', 'ignoreDeprecations'];
function runDiagnostics() {
console.log('TypeScript 7 호환성 사전 진단 시작...');
let hasError = false;
const packageFiles = globSync('/package.json', { ignore: '/node_modules/' });
for (const file of packageFiles) {
const content = JSON.parse(fs.readFileSync(file, 'utf8'));
const allDeps = { ...content.dependencies, ...content.devDependencies };
for (const dep of INCOMPATIBLE_DEPS) {
if (allDeps[dep]) {
console.warn([의존성 경고] ${file}: '${dep}' 패키지는 TS7 네이티브 API와 호환되지 않습니다.);
hasError = true;
}
}
}
const tsconfigFiles = globSync('/tsconfig*.json', { ignore: '/node_modules/' });
for (const file of tsconfigFiles) {
const rawContent = fs.readFileSync(file, 'utf8');
for (const opt of DEPRECATED_TSCONFIG_OPTIONS) {
if (rawContent.includes(opt)) {
console.error([설정 오류] ${file}: 무효화된 옵션 발견 -> '${opt}');
hasError = true;
}
}
}
if (hasError) process.exit(1);
}
runDiagnostics();
`
Transformers de AST customizados que dependem de ts.createProgram() ou ts.transform() também não funcionam. O TS 7.0 não aceita injeção de plugins JS externos. Essa lógica deve ser substituída por módulos com bindings Rust/C++, como SWC ou Babel, ou ser removida da etapa de compilação.
| Opção do compilador | Comportamento no TypeScript 6.0 | Comportamento no TypeScript 7.0 | Como resolver |
|---|---|---|---|
target |
Aviso ao usar es5 |
Hard Error (Interrupção da compilação) | Alterar para es2022 ou superior |
moduleResolution |
Permite a configuração node |
Hard Error | Alterar para bundler ou node16 |
baseUrl |
Permite uso isolado | Hard Error | Migrar para o uso isolado de compilerOptions.paths |
ignoreDeprecations |
Ignora avisos | Opção invalidada e erro | Remover a configuração completamente |
strict |
Valor padrão false |
Valor padrão true |
Definir valor explícito no tsconfig.json |
O TypeScript 7 tira proveito do modelo de threading do Go. Ele fornece novas opções: --checkers para processar a verificação de tipos em paralelo e --builders para controlar o build de referências de projetos. A equipe de engenharia do Slack combinou essas opções para reduzir o tempo de type checking de 20 minutos para 4,5 minutos. No entanto, se você alocar threads em excesso sem alinhar com o número de cores, o overhead de troca de contexto da CPU aumenta e o build quebra por OOM (Out of Memory).
É recomendável definir as threads com base na especificação da máquina runner usando a fórmula abaixo. Considerando o número de cores alocados da máquina virtual como , a memória total como , a memória reservada pelo SO como (), e a ocupação média de memória por worker como (), o número ideal de threads para um único projeto é calculado como:
N_{checkers} = minleft( C_{vCPU}, leftlfloor rac{M_{total} - M_{OS}}{M_{worker}} ight floor ight)A soma total de threads, , não deve exceder . Por exemplo, em um ambiente runner com 8 vCPU / 16GB, a configuração --checkers 4 e --builders 2 é adequada.
`yaml
name: Monorepo Parallel Typecheck
on:
push:
branches: [main]
jobs:
typecheck:
runs-on: ubuntu-latest-8-core
steps:
- name: Checkout Codebase
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Purge Legacy TS 6.0 Cache
run: find . -name "*.tsbuildinfo" -not -path "*/node_modules/*" -delete
- name: Execute TS 7 Parallel Check
run: npx tsc --build --checkers 4 --builders 2 --verbose
`
Há um ponto de atenção. O motor de compilação incremental do TS 7 não é compatível com o formato do arquivo de cache .tsbuildinfo do TS 6 legado. Se você não apagar os caches de versões antigas antes do build com find . -name "*.tsbuildinfo" -delete, ocorrerá um erro de falha de segmentação (segmentation fault).
O servidor de linguagem para editores também foi reformulado para um LSP baseado no binário em Go. De acordo com os resultados dos testes no AWS CodeBuild, em monorepos de grande escala, o tempo necessário para que o primeiro erro de tipo apareça ao abrir um arquivo caiu de 17,5 segundos para 1,3 segundo.
Para padronizar o ambiente do VS Code entre os membros da equipe, basta adicionar as seguintes configurações no arquivo .vscode/settings.json na raiz do monorepo:
`json
{
"typescript.tsdk": "node_modules/typescript/lib",
"js/ts.experimental.useTsgo": true,
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.preferences.preferTypeOnlyAutoImports": true,
"files.associations": {
"*.tsbuildinfo": "json"
}
}
`
Às vezes podem ocorrer conflitos com plugins de linguagens de template como Vue ou Svelte, fazendo com que a análise sintática falhe. Nesses casos, pressione Ctrl+Shift+P para abrir a paleta de comandos, selecione TypeScript: Select TypeScript Version... e altere temporariamente de volta para o motor do TS 6.0 enquanto trabalha.
Se o seu projeto contiver pacotes legados e você não puder atualizar o ESLint para o ambiente do TS 7 imediatamente, é possível contornar o problema usando uma arquitetura de motor duplo (dual engine), executando ambos os compiladores lado a lado. Dessa forma, você conecta a API do TS 6 às ferramentas de análise estática e deixa apenas a verificação de tipos e o build reais a cargo do binário nativo do TS 7.
Defina aliases de pacote no package.json para instalar ambos os compiladores simultaneamente:
`json
{
"name": "monorepo-root",
"private": true,
"devDependencies": {
"typescript": "npm:@typescript/typescript6@^6.0.2",
"@typescript/native": "npm:typescript@^7.0.2",
"eslint": "^9.0.0",
"typescript-eslint": "^8.0.0"
},
"scripts": {
"typecheck": "ts-native --build",
"typecheck:legacy": "tsc6 --noEmit",
"lint": "eslint ."
}
}
`
Nesse estado, é seguro anexar um script de shadow build à CI. Comparando o resultado do diagnóstico do TS 6 existente com o do TS 7 via diff, você pode monitorar se os resultados divergem em tipos de template literal ou em inferências de tipos condicionais.
`bash
#!/usr/bin/env bash
set -e
echo "=== 1. 기존 TS 6.0 컴파일러 진단 출력 생성 ==="
npx tsc6 --noEmit --pretty false > ./ts6-baseline.log 2>&1 || true
echo "=== 2. 신규 TS 7.0 네이티브 컴파일러 진단 출력 생성 ==="
npx --package @typescript/native tsc --noEmit --pretty false > ./ts7-output.log 2>&1 || true
echo "=== 3. 진단 결과 Diff 대조 검증 ==="
DIFF_RESULT=$(diff ./ts6-baseline.log ./ts7-output.log || true)
if [ -z "DIFF_RESULT"
exit 0
fi
`
Até que os problemas de compatibilidade da cadeia de ferramentas sejam resolvidos, o caminho mais realista é separar as funções de linter e de type checking. Ajustando as opções problemáticas com um script de pré-diagnóstico e regulando as threads de acordo com as especificações da infraestrutura de CI, você poderá aproveitar os ganhos de velocidade sem o infortúnio de paralisar a sua pipeline de deployment.