| name | typing-fix-protocol |
| description | Protocolo completo de scan, triagem e correção de erros TypeScript/JSDoc em repositório JS-first com @ts-check. Use ao executar o Full-Strict Roadmap lane por lane ou corrigir erros em arquivo específico. Contém comandos de triagem, cookbook por TS code, prioridade de cascata, estratégia de batch edit e casos especiais aprendidos em campo. |
Skill: typing-fix-protocol
Protocolo operacional para zerar erros TypeScript em repositório Node.js 24+ ESM com
// @ts-check e JSDoc. Complementa jsdoc-authoring (cookbook) e typing-node24-esm-tsserver
(arquitetura de lanes).
Regra absoluta: // @ts-nocheck é proibido. Jamais use para suprimir erros.
Quando usar esta skill
- Executar uma lane do Full-Strict Roadmap (ex:
src.inference_gateway)
- Corrigir erros de tipagem em um arquivo específico
- Auditar o estado atual de erros em múltiplos lanes
- Decidir a ordem de fix dentro de um arquivo com muitos erros misturados
Fase 1 — Scan e Triagem
1.1 — Medir o lane completo
npm run typecheck:strict:LANE 2>&1 | wc -l
npm run typecheck:strict:LANE 2>&1 \
| grep -oP '[^/\s]+\.(m?js|mts|ts)(?=\()' \
| sort | uniq -c | sort -rn | head -15
npm run typecheck:strict:LANE 2>&1 | grep -oP 'TS\d+' | sort | uniq -c | sort -rn
1.2 — Triagem de um arquivo
npm run typecheck:strict:LANE 2>&1 \
| grep "nome-do-arquivo" \
| sed 's/.*nome-do-arquivo//' \
| sort -t: -k1,1n | uniq
npm run typecheck:strict:LANE 2>&1 | grep "nome-do-arquivo" | wc -l
npm run typecheck:strict:LANE 2>&1 | grep "nome-do-arquivo" \
| grep -oP 'TS\d+' | sort | uniq -c | sort -rn
1.3 — Verificação pós-fix
npm run typecheck:strict:LANE 2>&1 | grep "nome-do-arquivo" | wc -l
npm run typecheck:strict:LANE 2>&1 | tail -5
for lane in src.logic agents scripts.ci scripts.setup tests.helpers scripts.build scripts.env src.validation tests.mocks scripts.analysis; do
count=$(npm run typecheck:strict:$lane 2>&1 | grep -c "error TS" || true)
echo "$lane: $count"
done
Fase 2 — Leitura do Arquivo
Regra: sempre leia o arquivo antes de editar. Para arquivos com erros em linhas espalhadas, faça
leituras paralelas por blocos de 80–120 linhas ao redor de cada linha de erro.
Estratégia de leitura eficiente
Dado um arquivo de 800 linhas com erros em: 47, 107, 152, 236, 311, 434, 492, 631, 687, 777, 944,
977
Batch 1 (paralelo): read_file(1-50) + read_file(95-170) + read_file(220-270)
Batch 2 (paralelo): read_file(290-360) + read_file(415-510) + read_file(615-700)
Batch 3 (paralelo): read_file(760-800) + read_file(930-1000)
O que procurar ao ler
| TS Code | O que procurar no arquivo |
|---|
| TS7006 | Assinatura de função/método (falta @param JSDoc) |
| TS7008 | constructor() { this.x = [] } sem anotação |
| TS7034 | const arr = [] sem tipo |
| TS7053 | const obj = {} seguido de obj[key] |
| TS18046 | catch (err) { err.message } — err é unknown |
| TS2339 | Acesso a propriedade em objeto sem typedef / objeto tipado como {} |
| TS2345 | .push(x) em array — indica never[] upstream |
| TS2488 | @returns {object} quando código faz for...of |
| TS8032 | Sub-@param sem @param pai declarado |
| typedef | {{ tipo } sem }} em @property de @typedef |
Fase 3 — Cookbook de Correções por Código
TS7006 — Parâmetro implicitamente any
function process(data, filePath) { ... }
items.map( s => s.trim())
items.filter( v => v.active)
Object.entries(obj).forEach( (_, v) => use(v))
new Set(arr.map( f => path.basename(f)))
arr.sort(( a, b) => a.value - b.value)
TS7008 — Membro de classe implicitamente any
this.items = [];
this.cache = {};
this.issues = { unused: [], duplicates: [], enumCandidates: [], typeCandidates: [] };
TS7034 — Variável never[]
const results = [];
const files = [];
TS7053 — Indexação de {}
const byFile = {};
const types = {};
const labels = {};
TS18046 — catch (err) unknown
} catch (err) {
const _e = (err);
console.error(_e.message);
}
TS2339 — Propriedade não existe
const snippet = ({
prefix: opts.prefix,
include: opts.include,
});
const analysisData = { files: [], issues: {}, dependencies: new Map() };
TS2345 — Push em never[] (SEMPRE corrija o upstream)
results.push( (item));
const results = [];
results.push(item);
TS2488 — Tipo não iterável
TS2552 — object.X (maiúscula)
object.fromEntries(entries);
object.keys(obj);
object.assign({}, a, b);
TS8032/TS8024 — JSDoc malformado
* @property {{ imports?: string[]} candidate ← bug: falta }}
* @property {{ imports?: string[], patterns?: string[], minHits?: number }} candidate
@param {object} → a classe que recebe analysisData
class ReportGenerator {
constructor(data) {
this.data = data;
}
}
Fase 4 — Ordem de Aplicação (Cascata)
Dentro de um arquivo, aplique na seguinte ordem para maximizar eliminação de cascata:
1. TS8032 / TS8024 / typedef malformado → raiz de cascatas de TS2339
2. TS7008 (this.x = []) → elimina TS2345 em pushes de instância
3. TS7034 (const arr = []) → elimina TS2345 em pushes/spreads
4. TS7053 (const obj = {}) → elimina TS7053 nos acessos
5. TS7006 (params sem tipo) → elimina TS2339 em chamadas
6. TS18046 (catch err unknown) → sem cascata
7. TS2345 / TS2339 residuais → resolver pontualmente
Fase 5 — Edição em Lote
Regra: uma única chamada multi_replace_string_in_file por arquivo
Agrupe TODOS os patches de um arquivo numa única chamada. Motivos:
- Edições sequenciais falham se a primeira deslocou linhas
- Uma única chamada é 5–10× mais rápida
- O
oldString é mais seguro em contexto não-modificado
Contexto mínimo no oldString
Inclua 3–5 linhas exclusivas: 2–3 antes do alvo + a linha alvo + 1–2 depois. Garante match único.
Para arquivos grandes: 3 rounds de leitura + 1 round de edição
Round 1 (paralelo): ler blocos A, B, C
Round 2 (paralelo): ler blocos D, E, F (baseado em erros com linhas maiores)
Round 3 (opcional): ler blocos caso ainda haja dúvidas
Round 4: multi_replace_string_in_file com todos os patches
Fase 6 — Casos Especiais
Emoji em catch blocks
replace_string_in_file falha silenciosamente quando o oldString contém emoji (encoding UTF-8
multi-byte). Use Python:
python3 -c "
import re, pathlib
f = pathlib.Path('scripts/analysis/arquivo.mjs')
txt = f.read_text(encoding='utf-8')
txt = txt.replace(
'} catch (err) {\n console.warn(\` ⚠️ Erro: \${err.message}\`);',
'} catch (err) {\n const _e = /** @type {any} */ (err);\n console.warn(\` ⚠️ Erro: \${_e.message}\`);'
)
f.write_text(txt, encoding='utf-8')
print('done')
"
this.issues com muitos sub-arrays — padrão DetectorClass
Objeto mais complexo que any[] simples. Use o typedef inline completo no construtor:
this.issues = {
unused: [],
duplicates: [],
magicValues: [],
redundantLet: [],
enumCandidates: [],
typeCandidates: [],
};
Isso elimina todos os this.issues.X.push(...) como TS2345 em cascata.
.map(v => ({ name: v.name, file: v.file })) com v implícito
vars.map( (v) => ({ name: v.name, file: v.file }));
JSDoc de typedef com objeto inline complexo
* @property {{ imports?: string[], patterns?: string[], sequences?: string[], minHits?: number, snippetName?: string }} candidate
* @property {{ imports?: string[]} candidate ← falta }}
Referência Rápida — Comandos de Verificação
npm run typecheck:strict:LANE 2>&1 | tail -5
npm run typecheck:strict:LANE 2>&1 | grep "arquivo.mjs"
npm run typecheck:strict:LANE 2>&1 | grep -c "error TS"
npm run typecheck:strict:LANE 2>&1 | grep -oP 'TS\d+' | sort | uniq -c | sort -rn
npm run typecheck:strict:LANE 2>&1 | grep -oP '[^/\s]+\.m?js(?=\()' | sort | uniq -c | sort -rn | head -10
npm run typecheck:strict:src.logic 2>&1 | tail -2
npm run typecheck:strict:scripts.analysis 2>&1 | tail -2
npm run typecheck:strict:agents 2>&1 | tail -2
npm run typecheck:strict:scripts.ci 2>&1 | tail -2
Skills Relacionadas
jsdoc-authoring — cookbook completo de JSDoc, guardrails, quando
usar typedef vs cast
typing-node24-esm-tsserver — arquitetura de lanes,
tsconfig strict por lane, configuração de tsserver
lsp-ops — navegação semântica via tsserver (go-to-definition,
referências, diagnósticos)
DOCUMENTAÇÃO/TIPAGEM E JSDOC/ROADMAP.md — estado atual do roadmap, lanes concluídas, próximas
prioridades