<h2>Preparando seu Projeto TypeScript para Publicação</h2>
<p>Antes de publicar uma biblioteca TypeScript, você precisa entender que um projeto pronto para distribuição não é simplesmente um repositório com código TypeScript compilado. É necessário configurar corretamente o ambiente, definir metadados apropriados e garantir que os consumidores da sua biblioteca recebam tanto o código compilado quanto as informações de tipo (type definitions) sem ambiguidades.</p>
<p>A primeira etapa é configurar seu <code>tsconfig.json</code> de forma que a compilação gere não apenas JavaScript, mas também os arquivos <code>.d.ts</code> (declaration files). Esses arquivos contêm as definições de tipo e são críticos para desenvolvedores que usam sua biblioteca em projetos TypeScript. Além disso, você precisa decidir qual será a estrutura de diretórios no seu pacote distribuído e como os consumidores importarão seu código.</p>
<h2>Configuração de TypeScript e Geração de Type Definitions</h2>
<h3>Estruturando o tsconfig.json</h3>
<p>O arquivo <code>tsconfig.json</code> é o coração da configuração de qualquer projeto TypeScript. Para uma biblioteca que será publicada, você deve focar em três aspectos: a geração automática de declarações de tipo, a escolha do alvo de compilação (ECMAScript version) e a definição clara dos diretórios de entrada e saída.</p>
<pre><code class="language-json">{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020"],
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
},
"include": ["src/*/"],
"exclude": ["node_modules", "dist", "*/.test.ts"]
}</code></pre>
<p>A opção <code>declaration: true</code> instrui o TypeScript a gerar um arquivo <code>.d.ts</code> para cada arquivo TypeScript compilado. <code>declarationMap: true</code> cria source maps para essas declarações, permitindo que desenvolvedores naveguem até o código-fonte original ao usar sua biblioteca em um IDE. O <code>target: "ES2020"</code> garante compatibilidade com navegadores modernos enquanto mantém características recentes de JavaScript. Note que <code>module: "ESNext"</code> permite que ferramentas de empacotamento como webpack e rollup façam tree-shaking, reduzindo o tamanho final do bundle dos consumidores.</p>
<h3>Exemplo Prático de Type Definitions</h3>
<p>Considere uma biblioteca simples de utilitários matemáticos. Seu arquivo fonte seria:</p>
<pre><code class="language-typescript">// src/math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export interface Calculator {
value: number;
add(n: number): Calculator;
multiply(n: number): Calculator;
}
export class ChainedCalculator implements Calculator {
value: number = 0;
constructor(initialValue: number = 0) {
this.value = initialValue;
}
add(n: number): Calculator {
this.value += n;
return this;
}
multiply(n: number): Calculator {
this.value *= n;
return this;
}
}</code></pre>
<p>Após executar <code>tsc</code>, você terá em <code>dist/math.d.ts</code>:</p>
<pre><code class="language-typescript">export declare function add(a: number, b: number): number;
export declare function multiply(a: number, b: number): number;
export interface Calculator {
value: number;
add(n: number): Calculator;
multiply(n: number): Calculator;
}
export declare class ChainedCalculator implements Calculator {
value: number;
constructor(initialValue?: number);
add(n: number): Calculator;
multiply(n: number): Calculator;
}</code></pre>
<p>Essa declaração é automaticamente gerada e garante que consumidores da sua biblioteca terão acesso completo a informações de tipo, mesmo se estiverem usando JavaScript puro ou TypeScript.</p>
<h2>Configuração do package.json e Estratégias de Export</h2>
<h3>Definindo Entry Points</h3>
<p>O <code>package.json</code> é o documento que descreve sua biblioteca para o npm. Para uma biblioteca TypeScript publicada, você precisa indicar qual arquivo é o ponto de entrada principal, onde estão as type definitions e, se aplicável, oferecer suporte a diferentes módulos (CommonJS, ES Modules, etc.).</p>
<pre><code class="language-json">{
"name": "@seu-nome/math-utils",
"version": "1.0.0",
"description": "Biblioteca de utilitários matemáticos com suporte total a TypeScript",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./math": {
"import": "./dist/math.mjs",
"require": "./dist/math.js",
"types": "./dist/math.d.ts"
}
},
"files": [
"dist",
"README.md",
"LICENSE"
],
"keywords": ["math", "typescript", "utils"],
"author": "Seu Nome",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/seu-nome/math-utils"
}
}</code></pre>
<p>O campo <code>exports</code> é uma das inovações mais importantes na eclosfera do Node.js. Ele permite que você defina múltiplos pontos de entrada e especifique qual arquivo usar para diferentes contextos (importações ES modules vs CommonJS). Isso é crucial para compatibilidade máxima. O campo <code>types</code> aponta para onde encontrar as declarações de tipo do ponto de entrada principal.</p>
<h3>Estrutura de Exportação Modular</h3>
<p>Se sua biblioteca é grande, você pode oferecer importações granulares. Isso reduz o tamanho dos bundles dos consumidores. Suponha que sua estrutura de diretórios seja:</p>
<pre><code>src/
├── index.ts
├── math.ts
├── string.ts
└── array.ts</code></pre>
<p>Com o <code>exports</code> apropriado no <code>package.json</code>, consumidores podem fazer:</p>
<pre><code class="language-typescript">// Importação do ponto de entrada principal
import { add, multiply } from '@seu-nome/math-utils';
// Ou importações granulares
import { add } from '@seu-nome/math-utils/math';
import { capitalize } from '@seu-nome/math-utils/string';</code></pre>
<p>Para isso funcionar, cada arquivo em <code>src/</code> deve ter seu próprio ponto de entrada em <code>dist/</code>, e o <code>package.json</code> deve listar todos eles na seção <code>exports</code>. Seu script de build (usando tsc ou outra ferramenta) deve gerar tanto <code>.js</code> quanto <code>.mjs</code> para máxima compatibilidade.</p>
<h2>Compatibilidade e Versionamento Semântico</h2>
<h3>Entendendo Mudanças Quebradoras vs Compatíveis</h3>
<p>A compatibilidade de uma biblioteca TypeScript vai além de apenas manter a mesma interface de função. Inclui a compatibilidade estrutural de tipos, que é o sistema de tipos do TypeScript. Uma mudança é considerada "quebradora" (breaking change) se força consumidores a atualizar seu código para continuar usando sua biblioteca.</p>
<p>Exemplos de mudanças <strong>compatíveis</strong>:</p>
<ul>
<li>Adicionar um novo parâmetro opcional a uma função</li>
<li>Adicionar uma propriedade opcional a uma interface</li>
</ul>
<p>- Alargar o tipo de retorno (ex: <code>number</code> → <code>number | string</code>)</p>
<ul>
<li>Adicionar novos exports sem remover os antigos</li>
</ul>
<p>Exemplos de mudanças <strong>quebradoras</strong>:</p>
<ul>
<li>Remover ou renomear uma função ou classe exportada</li>
<li>Tornar um parâmetro obrigatório quando era opcional</li>
<li>Estreitar o tipo de um parâmetro</li>
<li>Remover uma propriedade de uma interface exportada</li>
</ul>
<h3>Versionamento Semântico na Prática</h3>
<pre><code class="language-json">{
"version": "2.3.1"
}</code></pre>
<p>Essa string segue o padrão MAJOR.MINOR.PATCH. MAJOR é incrementado para mudanças quebradoras, MINOR para novas features compatíveis com versões anteriores, e PATCH para correções de bugs. Se sua versão é 2.3.1 e você introduz uma mudança quebradora, a próxima versão deve ser 3.0.0. Se apenas adiciona uma função nova, é 2.4.0. Se corrige um bug, é 2.3.2.</p>
<pre><code class="language-typescript">// Versão 1.0.0 - Sua biblioteca original
export function process(data: string): string {
return data.toUpperCase();
}
// Versão 1.1.0 - Adiciona parâmetro opcional (compatível)
export function process(data: string, separator?: string): string {
return data.toUpperCase() + (separator || '');
}
// Versão 2.0.0 - Remove a função antiga e cria uma nova (quebradora)
export function transform(data: string, options: { uppercase?: boolean } = {}): string {
return options.uppercase !== false ? data.toUpperCase() : data;
}</code></pre>
<p>Ao publicar no npm, você comunica essa história através das tags de versão no seu repositório. Consumidores que especificam <code>"@seu-nome/math-utils": "^1.1.0"</code> receberão atualizações até (mas não incluindo) versão 2.0.0 automaticamente.</p>
<h2>Construindo e Testando sua Biblioteca para Publicação</h2>
<h3>Script de Build Profissional</h3>
<p>Um script de build deve não apenas compilar TypeScript para JavaScript, mas também gerar as variantes necessárias (CommonJS e ES Modules) e preparar os arquivos de declaração. Uma abordagem moderna usa <code>tsc</code> com scripts auxiliares:</p>
<pre><code class="language-json">{
"scripts": {
"build": "npm run clean && npm run compile && npm run validate-types",
"clean": "rm -rf dist",
"compile": "tsc",
"validate-types": "tsc --noEmit",
"test": "jest",
"prepublishOnly": "npm run test && npm run build",
"lint": "eslint src --ext .ts"
}
}</code></pre>
<p>O script <code>prepublishOnly</code> é especial: ele é executado automaticamente pelo npm antes de publicar seu pacote, garantindo que você nunca publique uma versão sem testes passando e sem compilação bem-sucedida. O <code>validate-types</code> roda TypeScript sem emitir arquivos (apenas fazendo type-checking), o que é rápido e garante que não há erros de tipo.</p>
<h3>Testando Compatibilidade com Consumidores</h3>
<p>Antes de publicar, você deve testar como seus consumidores experimentarão a biblioteca. Uma prática excelente é testar tanto em projetos TypeScript quanto em projetos JavaScript:</p>
<pre><code class="language-typescript">// tests/integration.test.ts
import { add, multiply, ChainedCalculator } from '../src/math';
describe('Math Utils Integration', () => {
test('add function works correctly', () => {
expect(add(2, 3)).toBe(5);
});
test('ChainedCalculator allows method chaining', () => {
const result = new ChainedCalculator(5)
.add(3)
.multiply(2)
.value;
expect(result).toBe(16);
});
test('types are correctly exposed', () => {
const calc: ChainedCalculator = new ChainedCalculator();
expect(calc).toBeDefined();
});
});</code></pre>
<p>Além dos testes unitários, você pode criar um projeto de teste separado que importa sua biblioteca localmente (usando <code>npm link</code> ou <code>npm pack</code>) e verifica se os tipos funcionam corretamente em um ambiente real:</p>
<pre><code class="language-typescript">// test-consumer/index.ts
import { add, ChainedCalculator } from 'math-utils';
// Isso deve compilar sem erros se os tipos estão corretos
const result: number = add(1, 2);
const calc = new ChainedCalculator();
// calc é do tipo Calculator aqui, TypeScript sabe disso
const chainedResult: number = calc.add(5).multiply(2).value;</code></pre>
<h2>Conclusão</h2>
<p>Publicar uma biblioteca TypeScript profissional envolve três pilares principais. Primeiro, <strong>configurar corretamente a geração de type definitions</strong> através do <code>tsconfig.json</code>, garantindo que consumidores recebam informações de tipo precisas e completas — isso diferencia uma biblioteca TypeScript competente de uma genérica. Segundo, <strong>dominar o <code>package.json</code> e o campo <code>exports</code></strong>, permitindo que diferentes tipos de consumidores (CommonJS, ES modules, TypeScript puro, JavaScript puro) usem sua biblioteca sem fricção. Terceiro, <strong>respeitar o versionamento semântico e testar compatibilidade</strong>, pois a reputação de sua biblioteca depende de confiabilidade — quebras inesperadas alienam usuários rapidamente.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook: Declaration Files</a></li>
<li><a href="https://docs.npmjs.com/cli/v9/configuring-npm/package-json" target="_blank" rel="noopener noreferrer">npm package.json documentation</a></li>
<li><a href="https://nodejs.org/api/packages.html#packages_exports" target="_blank" rel="noopener noreferrer">Node.js Package Exports documentation</a></li>
<li><a href="https://semver.org/" target="_blank" rel="noopener noreferrer">Semantic Versioning 2.0.0</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html" target="_blank" rel="noopener noreferrer">TypeScript Library Development Best Practices</a></li>
</ul>
<p><!-- FIM --></p>