Documentação do TypeScript
1. Fundamentos do TypeScript
- Superset do JavaScript
- Tipagem estática opcional
- Transpilação para JavaScript
2. Tipos Primitivos
- string, number, boolean
- null e undefined
- any (evitar sempre que possível)
- unknown (alternativa mais segura ao any)
- void (usado em funções que não retornam valor)
- never (para funções que nunca retornam)
3. Tipos Avançados
- Arrays e Tuplas (string[], [number, string])
- Enums (define conjuntos de valores fixos)
- Union & Intersection Types (string | number, A & B)
- Type Aliases e Interfaces (type vs interface)
- Generics (Array<T>, Promise<T>)
- Type Assertions (as, <Type>value)
4. Orientação a Objetos
- Classes e Modificadores (public, private, protected)
- Herança e Implementação de Interfaces
- Métodos e Propriedades Estáticas
- Getters e Setters
5. Manipulação de Código
- Namespaces e Módulos (import/export)
- Decorators (para metaprogramação)
- Tipagem Estrutural
6. Ferramentas e Configuração
- Arquivo tsconfig.json (configuração do compilador)
- Compilador tsc (TypeScript Compiler)
- Linting e Formatação (ESLint, Prettier)
7. Integração com Frameworks
- Node.js (tipagem com @types/node)
- React (tsx, React.FC<T>)
- Angular (forte integração com TypeScript)
8. Boas Práticas
- Evitar any sempre que possível
- Usar interfaces para contratos de dados
- Preferir readonly para propriedades imutáveis
- Documentação com JSDoc
1. Fundamentos do TypeScript
TypeScript é uma linguagem que expande o JavaScript adicionando tipagem estática e recursos avançados. Ele foi criado pela Microsoft e se tornou muito popular para desenvolvimento web, especialmente em projetos grandes.
Agora, vamos entender os três conceitos fundamentais do TypeScript:
1.1 Superset do JavaScript
O que significa ser um superset?
TypeScript é um superset de JavaScript, o que significa que todo código JavaScript válido também é válido em TypeScript. Isso facilita a adoção da linguagem, pois você pode começar usando JavaScript puro e, aos poucos, adicionar funcionalidades do TypeScript.
Exemplo: Código JavaScript puro válido em TypeScript:
function soma(a, b) {
return a + b;
}
console.log(soma(2, 3)); // 5
Esse código funciona tanto em JavaScript quanto em TypeScript.
Expansão do JavaScript:
TypeScript adiciona novos recursos que o JavaScript não tem, como:
- Tipagem estática (explicada abaixo)
- Interfaces e Generics
- Modificadores de acesso (private, protected, public)
- Decorators
Esses recursos ajudam a melhorar a segurança e a organização do código.
1.2 Tipagem Estática Opcional
O que é tipagem estática?
Em JavaScript, os tipos das variáveis são dinâmicos, ou seja, podem mudar em tempo de execução:
let x = "Olá";
x = 10; // JavaScript permite isso, mas pode causar erros inesperados
Já em TypeScript, podemos definir tipos explicitamente, garantindo que as variáveis sempre contenham valores esperados:
let x: string = "Olá";
x = 10; // Erro: Type 'number' is not assignable to type 'string'
Benefícios da tipagem estática:
- Evita erros em tempo de execução
- Facilita a refatoração do código
- Melhora a legibilidade e a manutenção
- Ajuda ferramentas como VS Code a oferecer sugestões inteligentes (IntelliSense)
Tipagem opcional:
TypeScript não obriga você a tipar tudo. Se você não especificar um tipo, ele tentará inferir automaticamente:
let nome = "Maria"; // TypeScript entende que é uma string
nome = 42; // Erro: Type 'number' is not assignable to type 'string'
1.3 Transpilação para JavaScript
Por que transpilação?
Os navegadores e runtimes como Node.js não entendem TypeScript diretamente. Por isso, o código TypeScript precisa ser transpilado para JavaScript antes de ser executado.
Como funciona a transpilação?
O TypeScript Compiler (tsc) converte o código TypeScript para JavaScript puro:
Código TypeScript:
const mensagem: string = "Olá, TypeScript!";
console.log(mensagem);
Código JavaScript gerado após a transpilação:
const mensagem = "Olá, TypeScript!";
console.log(mensagem);
Perceba que os tipos (string) desaparecem no JavaScript final. Isso acontece porque os tipos existem apenas no tempo de desenvolvimento, ajudando o programador, mas não impactam o código final.
Configuração da transpilação (tsconfig.json):
Podemos personalizar como o TypeScript é convertido para JavaScript através do arquivo tsconfig.json. Um exemplo básico:
{
"compilerOptions": {
"target": "ES6", // Define a versão do JavaScript gerado
"outDir": "dist", // Pasta de saída do código JavaScript
"strict": true // Habilita verificações rigorosas de tipo
}
}
Isso garante que o código gerado seja compatível com a versão desejada do JavaScript e siga regras de tipagem mais seguras.
Conclusão
TypeScript é um superset do JavaScript, adicionando tipagem estática opcional para evitar erros e melhorar a produtividade. Como os navegadores não entendem TypeScript, ele precisa ser transpilado para JavaScript antes de ser executado.
2. Tipos Primitivos no TypeScript
Os tipos primitivos são os tipos básicos de dados que representam valores simples. Eles são fundamentais para garantir segurança no código e evitar erros inesperados.
2.1 string, number e boolean
string: Representa textos e cadeias de caracteres.
let nome: string = "João";
let mensagem: string = `Olá, ${nome}!`; // Template string
➜ Se tentarmos atribuir outro tipo, TypeScript gera um erro:
nome = 123; // Erro: Type 'number' is not assignable to type 'string'
number: Representa valores numéricos (inteiros ou decimais).
let idade: number = 30;
let temperatura: number = 36.5;
let hexadecimal: number = 0xff; // Suporte a hexadecimal
➜ O TypeScript aceita inteiros, decimais, hexadecimais e binários.
boolean: Representa valores true ou false.
let ativo: boolean = true;
ativo = false;
2.2 null e undefined
O TypeScript trata null e undefined de forma especial.
undefined: Representa uma variável que foi declarada, mas não recebeu valor.
let x: undefined;
console.log(x); // undefined
null: Representa a ausência intencional de um valor.
let y: null = null;
Por padrão, o TypeScript pode impedir que variáveis tenham null ou undefined a menos que seja explicitamente permitido:
let nome: string = null; // Erro se o modo "strictNullChecks" estiver ativado!
Se quisermos permitir null, podemos usar Union Types:
let nome: string | null = "Maria";
nome = null; // Agora isso é permitido
2.3 any (evitar sempre que possível!)
O tipo any desativa a verificação de tipos, permitindo que a variável contenha qualquer valor.
let valor: any = "Olá";
valor = 42;
valor = true;
Problema com any: Ele elimina as vantagens do TypeScript, pois o código perde segurança e previsibilidade.
Quando usar any?
- Quando não sabemos o tipo exato dos dados (por exemplo, dados vindos de uma API desconhecida).
- Quando migramos código JavaScript para TypeScript e ainda não adicionamos tipagem correta.
Alternativa ao any: unknown (veja abaixo 👇)
2.4 unknown (alternativa mais segura ao any)
unknown é um tipo semelhante ao any, mas com mais segurança.
let dado: unknown;
dado = "Olá";
dado = 42;
dado = true;
A diferença é que não podemos acessar propriedades ou chamar métodos sem verificar o tipo primeiro:
dado.toUpperCase(); // Erro: Object is of type 'unknown'
Para usar um valor (unknown), precisamos primeiro fazer uma verificação de tipo:
if (typeof dado === "string") {
console.log(dado.toUpperCase()); // Agora funciona!
}
✅ Melhor prática: Prefira unknown em vez de any, pois obriga você a validar os dados antes de usá-los.
2.5 void (para funções que não retornam valor)
O tipo void é usado para indicar que uma função não retorna um valor.
function logMensagem(mensagem: string): void {
console.log(mensagem);
}
- Se tentarmos retornar algo de uma função void, TypeScript gera um erro:
function erro(): void { return "Erro!"; // ❌ Erro: Type 'string' is not assignable to type 'void' } - O
voidtambém pode ser usado em variáveis, mas raramente é útil:let resultado: void = undefined; // Permitido, mas pouco prático
2.6 never (para funções que nunca retornam)
O tipo never é usado quando uma função nunca retorna um valor porque ela gera um erro ou entra em um loop infinito.
Exemplo 1: Função que lança um erro
function erro(mensagem: string): never {
throw new Error(mensagem);
}
Essa função nunca retorna nada porque interrompe a execução do programa.
Exemplo 2: Loop infinito
function loopInfinito(): never {
while (true) {
console.log("Executando...");
}
}
Como a função nunca termina, seu retorno é never.
✅ Quando usar never?
- Em funções que sempre lançam exceções.
- Em funções que nunca alcançam um ponto final de execução.
Resumo
| Tipo | Descrição | Exemplo |
|---|---|---|
| string | Texto (cadeia de caracteres) | "Hello" |
| number | Números inteiros e decimais | 42, 3.14 |
| boolean | Valores lógicos | true, false |
| null | Ausência intencional de valor | null |
| undefined | Variável sem valor atribuído | undefined |
| any | Pode conter qualquer valor (evitar) | "texto", 42, true |
| unknown | Tipo desconhecido, exige verificação antes do uso | "string", 42, true (mas com segurança) |
| void | Função sem retorno | function log(): void {} |
| never | Função que nunca retorna | throw new Error("Erro") |
Conclusão
- Use string, number e boolean sempre que possível.
- Evite any e prefira unknown quando o tipo não for conhecido.
- Use void para funções sem retorno.
- Use never para funções que nunca retornam um valor válido.
Isso garante código mais seguro, legível e fácil de manter! 🚀
3. Tipos Avançados no TypeScript
O TypeScript fornece tipos mais sofisticados para aumentar a flexibilidade e segurança do código. Vamos explorar cada um deles.
3.1 Arrays e Tuplas
Arrays
No TypeScript, podemos definir arrays tipados para garantir que todos os elementos tenham um tipo específico.
let numeros: number[] = [1, 2, 3, 4, 5]; // Apenas números
let nomes: string[] = ["Alice", "Bob", "Carlos"]; // Apenas strings
Outra forma de definir arrays é usando Generics (Array<T>):
let numeros: Array<number> = [10, 20, 30]; // Equivalente a number[]
📌 Observação: O TypeScript impede operações inválidas em arrays tipados:
numeros.push("Texto"); // Erro: Type 'string' is not assignable to type 'number'
Tuplas
Tuplas são um tipo especial de array com um número fixo de elementos e tipos específicos para cada posição.
let pessoa: [string, number] = ["Alice", 30];
📌 A diferença entre arrays e tuplas é que tuplas têm uma estrutura rígida, então a ordem e os tipos dos elementos devem ser seguidos.
pessoa = [30, "Alice"]; // Erro: Type 'number' is not assignable to type 'string'
As tuplas também podem ter elementos opcionais e valores variáveis:
let usuario: [number, string, boolean?] = [1, "Carlos"]; // O boolean é opcional
usuario = [2, "Maria", true]; // Também válido
3.2 Enums
Enums são usados para definir um conjunto de valores fixos e nomeados, tornando o código mais legível.
enum StatusPedido {
Pendente,
Enviado,
Entregue
}
let statusAtual: StatusPedido = StatusPedido.Enviado;
console.log(statusAtual); // 1 (os valores padrão são números, começando em 0)
Podemos atribuir valores específicos:
enum Status {
Pendente = "PENDENTE",
Enviado = "ENVIADO",
Entregue = "ENTREGUE"
}
let pedido: Status = Status.Entregue;
console.log(pedido); // "ENTREGUE"
📌 Boas práticas:
- Use strings em enums para evitar problemas com valores numéricos inesperados.
- Evite enums quando possível – prefira const com objetos.
Exemplo alternativo sem enum:
const StatusPedido = {
Pendente: "PENDENTE",
Enviado: "ENVIADO",
Entregue: "ENTREGUE"
} as const;
let pedido: keyof typeof StatusPedido = "Pendente";
3.3 Union & Intersection Types
Union Types (|)
Permitem que uma variável aceite mais de um tipo.
let idade: number | string;
idade = 25;
idade = "25 anos"; // Ambos são válidos
Útil para tratar valores dinâmicos, como entrada de usuários.
function mostrarId(id: number | string) {
console.log(`ID: ${id}`);
}
mostrarId(123);
mostrarId("ABC123");
📌 Verificação de tipo necessária
function processar(valor: number | string) {
if (typeof valor === "string") {
console.log(valor.toUpperCase());
} else {
console.log(valor.toFixed(2));
}
}
Intersection Types (&)
Permitem combinar múltiplos tipos.
type Pessoa = { nome: string };
type Funcionario = { cargo: string };
type Empregado = Pessoa & Funcionario;
let emp: Empregado = { nome: "João", cargo: "Desenvolvedor" };
📌 Uso comum: Para compor objetos complexos e herança de tipos.
3.4 Type Aliases vs Interfaces
Type Aliases (type)
Permitem criar nomes personalizados para tipos existentes.
type ID = string | number;
let userId: ID = 123;
Interfaces (interfaces)
Definem a estrutura de objetos.
interface Usuario {
nome: string;
idade: number;
}
let user: Usuario = { nome: "Carlos", idade: 28 };
📌 Diferenças entre type e interface:
| Feature | type | interface |
|---|---|---|
| Uso para objetos | ✅ | ✅ |
| Uso para primitivos (string, number) | ✅ | ❌ |
| Extensível (extends) | ❌ | ✅ |
| Combinação (&) | ✅ | ✅ |
3.5 Generics (<T>)
Generics permitem criar funções e classes reutilizáveis sem definir tipos fixos.
Exemplo 1: Função Genérica
function identidade<T>(valor: T): T {
return valor;
}
console.log(identidade<string>("Teste"));
console.log(identidade<number>(123));
📌 Vantagem: Podemos usar identidade() para qualquer tipo sem perder a segurança.
Exemplo 2: Array Genérico
function primeiroElemento<T>(array: T[]): T {
return array[0];
}
console.log(primeiroElemento<string>(["a", "b", "c"])); // "a"
console.log(primeiroElemento<number>([1, 2, 3])); // 1
Exemplo 3: Classe Genérica
class Caixa<T> {
conteudo: T;
constructor(conteudo: T) {
this.conteudo = conteudo;
}
}
let caixaDeNumeros = new Caixa<number>(100);
let caixaDeTexto = new Caixa<string>("Olá");
✅ Uso comum:
- Trabalhar com arrays de diferentes tipos (Array<T>)
- Criar funções flexíveis
- Criar classes reutilizáveis
3.6 Type Assertions (as e <Type>)
Type Assertions permitem informar ao TypeScript que um valor tem um tipo específico.
let valor: any = "Olá, TypeScript!";
let tamanho: number = (valor as string).length;
console.log(tamanho); // 17
📌 Outro modo:
let tamanho2: number = (<string>valor).length;
✅ Quando usar?
- Quando sabemos que um valor tem um tipo específico, mas o TypeScript não consegue inferir.
- Ao trabalhar com o DOM:
let input = document.getElementById("meuInput") as HTMLInputElement; console.log(input.value);
Conclusão
Resumo dos conceitos principais
| Tipo Avançado | Descrição |
|---|---|
| Arrays & Tuplas | Estruturas ordenadas de dados |
| Enums | Conjuntos de valores fixos |
Union (|) |
Combina múltiplos tipos |
Intersection (&) |
Combina múltiplos tipos |
| Type vs Interface | Criam tipos personalizados |
| Generics | Código reutilizável para diferentes tipos |
| Type Assertions | Força a interpretação de um tipo |
Esses conceitos tornam o TypeScript mais poderoso e flexível! 🚀
A Orientação a Objetos (OO) no TypeScript traz mais organização e reutilização para o código. Vamos explorar Classes, Modificadores, Herança, Interfaces, Métodos Estáticos, Getters e Setters com exemplos práticos.
4. Orientação a Objetos no TypeScript
O TypeScript estende os recursos de classes do JavaScript adicionando tipagem estática, modificadores de acesso, herança e interfaces.
4.1 Classes e Modificadores de Acesso
Uma classe é um modelo para criar objetos. No TypeScript, podemos definir propriedades e métodos dentro de uma classe.
Criando uma Classe
class Pessoa {
nome: string;
idade: number;
constructor(nome: string, idade: number) {
this.nome = nome;
this.idade = idade;
}
apresentar(): string {
return `Olá, meu nome é ${this.nome} e tenho ${this.idade} anos.`;
}
}
const pessoa1 = new Pessoa("Alice", 25);
console.log(pessoa1.apresentar());
Modificadores de Acesso (public, private, protected)
Os modificadores de acesso controlam como as propriedades e métodos podem ser acessados dentro e fora da classe.
| Modificador | Acesso na própria classe | Acesso em subclasses | Acesso fora da classe |
|---|---|---|---|
| public (padrão) | ✅ | ✅ | ✅ |
| private | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ❌ |
Exemplo de Modificadores
class ContaBancaria {
public titular: string; // Acessível de qualquer lugar
private saldo: number; // Só acessível dentro da classe
protected tipo: string; // Acessível na classe e subclasses
constructor(titular: string, saldoInicial: number, tipo: string) {
this.titular = titular;
this.saldo = saldoInicial;
this.tipo = tipo;
}
public depositar(valor: number): void {
this.saldo += valor;
console.log(`Depósito de R$${valor}. Novo saldo: R$${this.saldo}`);
}
private exibirSaldo(): void {
console.log(`Saldo atual: R$${this.saldo}`);
}
}
const conta = new ContaBancaria("João", 1000, "Corrente");
conta.depositar(500);
// conta.saldo = 5000; // ❌ Erro: saldo é privado!
4.2 Herança e Implementação de Interfaces
A herança permite que uma classe herde propriedades e métodos de outra.
Exemplo de Herança (extends)
class Animal {
nome: string;
constructor(nome: string) {
this.nome = nome;
}
emitirSom(): void {
console.log("Som genérico de um animal...");
}
}
class Cachorro extends Animal {
raca: string;
constructor(nome: string, raca: string) {
super(nome);
this.raca = raca;
}
emitirSom(): void {
console.log("Au Au!"); // Sobrescrevendo método
}
}
const dog = new Cachorro("Rex", "Labrador");
dog.emitirSom(); // "Au Au!"
console.log(dog.nome); // "Rex"
📌 O que acontece aqui?
- A classe Cachorro herda a propriedade nome e o método emitirSom() da classe Animal.
- O método emitirSom() foi sobrescrito (polimorfismo).
- O super(nome) chama o construtor da classe pai (Animal).
Interfaces (implements)
Interfaces definem um contrato que uma classe deve seguir.
interface IUsuario {
nome: string;
idade: number;
logar(): boolean;
}
class Usuario implements IUsuario {
nome: string;
idade: number;
constructor(nome: string, idade: number) {
this.nome = nome;
this.idade = idade;
}
logar(): boolean {
console.log(`${this.nome} está logado!`);
return true;
}
}
const usuario = new Usuario("Maria", 30);
usuario.logar();
📌 Quando usar extends e implements?
- extends: Herda propriedades e métodos de uma classe.
- implements: Garante que uma classe siga um contrato, sem herdar implementações.
4.3 Métodos e Propriedades Estáticas (static)
Os métodos e propriedades estáticas pertencem à classe, não aos objetos.
Exemplo
class Util {
static versao: string = "1.0";
static saudacao(): string {
return "Bem-vindo ao sistema!";
}
}
console.log(Util.versao); // "1.0"
console.log(Util.saudacao()); // "Bem-vindo ao sistema!"
📌 Uso comum de static
- Criar constantes globais (Math.PI, Date.now()).
- Métodos auxiliares que não dependem de instâncias.
4.4 Getters e Setters
Getters (get) e setters (set) são usados para acessar e modificar propriedades de forma controlada.
Exemplo
class Produto {
private _preco: number;
constructor(preco: number) {
this._preco = preco;
}
get preco(): number {
return this._preco;
}
set preco(valor: number) {
if (valor <= 0) {
console.log("O preço deve ser maior que zero!");
return;
}
this._preco = valor;
}
}
const p = new Produto(100);
console.log(p.preco); // Usa o getter -> 100
p.preco = 150; // Usa o setter
console.log(p.preco); // 150
p.preco = -50; // "O preço deve ser maior que zero!"
📌 Vantagens dos Getters e Setters
- Protegem a modificação de dados.
- Permitem lógica adicional ao acessar/modificar propriedades.
- Mantêm a encapsulação dos dados internos.
Resumo
| Conceito | Descrição |
|---|---|
| Classes | Definem modelos para criar objetos |
| Modificadores | public (acessível em qualquer lugar), private (somente dentro da classe), protected (acessível em subclasses) |
| Herança | extends permite herdar propriedades e métodos |
| Interfaces | implements define um contrato que a classe deve seguir |
| Métodos Estáticos | static permite métodos e propriedades sem precisar criar instância |
| Getters/Setters | Métodos especiais para acessar/modificar propriedades com validação |
Conclusão
A Orientação a Objetos no TypeScript oferece encapsulamento, reutilização de código e organização. 🚀
5. Manipulação de Código no TypeScript
5.1 Namespaces e Módulos (import/export)
Namespaces
Os namespaces eram usados no TypeScript para organizar o código e evitar conflitos de nomes em projetos grandes. Hoje, módulos são mais recomendados, mas namespaces ainda podem ser úteis em certos cenários.
📌 Exemplo de Namespace
namespace Utils {
export function saudacao(nome: string): string {
return `Olá, ${nome}!`;
}
export const versao = "1.0";
}
console.log(Utils.saudacao("Alice"));
console.log(Utils.versao);
- A palavra-chave export torna a função e a constante acessíveis fora do namespace.
- Para acessar os membros do namespace, usamos Utils.saudacao() e Utils.versao.
⚠ Nota: Namespaces não são mais recomendados para projetos modernos, pois os módulos (import/export) são mais poderosos e escaláveis.
Módulos (import/export)
Os módulos permitem dividir o código em arquivos reutilizáveis e organizados.
📌 Exemplo de Módulo
Criamos dois arquivos:
📌 Arquivo: utils.ts (módulo exportador)
export function saudacao(nome: string): string {
return `Olá, ${nome}!`;
}
export const versao = "1.0";
📌 Arquivo: main.ts (módulo importador)
import { saudacao, versao } from "./utils";
console.log(saudacao("Alice"));
console.log(versao);
✅ Vantagens dos módulos (import/export)
- Melhor suporte em projetos grandes.
- Permite importar apenas o que é necessário.
- Funciona nativamente no ES6+ e em ferramentas como Webpack e Node.js.
5.2 Decorators (Metaprogramação)
Os Decorators são um recurso avançado do TypeScript para modificar classes, métodos, propriedades e parâmetros em tempo de execução.
📌 ⚠ Importante:
- Decorators precisam que o (experimentalDecorators) esteja ativado no tsconfig.json.
- São muito usados em frameworks como Angular e bibliotecas como TypeORM.
Exemplo de Decorator de Classe
Criamos um decorator que adiciona um log quando uma classe é instanciada.
function LogarInstancia(construtor: Function) {
console.log(`Classe ${construtor.name} foi instanciada.`);
}
@LogarInstancia
class Pessoa {
constructor(public nome: string) {}
}
const p = new Pessoa("Carlos"); // "Classe Pessoa foi instanciada."
📌 Explicação:
- @LogarInstancia é um decorator de classe que executa código quando a classe é carregada.
Exemplo de Decorator de Método
Criamos um decorator que registra chamadas de métodos.
function LogarMetodo(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const metodoOriginal = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Chamando método ${propertyKey} com argumentos:`, args);
return metodoOriginal.apply(this, args);
};
}
class Calculadora {
@LogarMetodo
somar(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculadora();
console.log(calc.somar(2, 3)); // "Chamando método somar com argumentos: [2,3]"
📌 Explicação:
- @LogarMetodo intercepta chamadas do método somar(), registrando seus parâmetros.
Exemplo de Decorator de Propriedade
Criamos um decorator que valida se um valor é positivo.
function ValidaNumero(target: any, propertyKey: string) {
let valor: number;
Object.defineProperty(target, propertyKey, {
get: () => valor,
set: (novoValor: number) => {
if (novoValor < 0) {
throw new Error("O valor não pode ser negativo!");
}
valor = novoValor;
}
});
}
class Conta {
@ValidaNumero
saldo!: number;
}
const conta = new Conta();
conta.saldo = 100;
console.log(conta.saldo); // 100
// conta.saldo = -50; // ❌ Erro: "O valor não pode ser negativo!"
📌 Explicação:
- O getter/setter personalizado impede que saldo receba valores negativos.
✅ Onde os Decorators são usados?
- Frameworks como Angular (@Component, @Injectable).
- ORMs como TypeORM (@Entity, @Column).
- Validação de entrada de dados.
5.3 Tipagem Estrutural
O TypeScript usa "tipagem estrutural" ao invés de tipagem nominal. Isso significa que o que importa não é o nome do tipo, mas sua estrutura.
📌 Exemplo de Tipagem Estrutural
class Carro {
modelo: string;
ano: number;
constructor(modelo: string, ano: number) {
this.modelo = modelo;
this.ano = ano;
}
}
interface Veiculo {
modelo: string;
ano: number;
}
let meuCarro: Veiculo = new Carro("Fusca", 1970);
📌 Explicação:
- O objeto meuCarro é da interface Veiculo, mas recebe um objeto da classe Carro.
- Isso funciona porque as estruturas são compatíveis (mesmos atributos).
✅ Vantagens da Tipagem Estrutural
- Maior flexibilidade no uso de objetos.
- Facilita o uso de diferentes classes que tenham a mesma estrutura.
Resumo
| Conceito | Descrição |
|---|---|
| Namespaces | Organização de código (não recomendados para novos projetos) |
| Módulos | import/export para dividir código em arquivos reutilizáveis |
| Decorators | Metaprogramação para modificar classes, métodos e propriedades |
| Tipagem Estrutural | Comparação de tipos baseada na estrutura e não no nome |
Conclusão
A manipulação de código no TypeScript ajuda a criar código mais organizado, reutilizável e dinâmico. 🚀
6. Ferramentas e Configuração do TypeScript
O TypeScript oferece um ecossistema robusto com várias ferramentas essenciais para desenvolvimento profissional. Aqui estão os três pilares fundamentais:
- tsconfig.json – Configuração do compilador TypeScript.
- tsc (TypeScript Compiler) – Transpila TypeScript para JavaScript.
- Linting e Formatação (ESLint, Prettier) – Mantém o código limpo e padronizado.
6.1 tsconfig.json (Configuração do Compilador)
O arquivo tsconfig.json é a configuração central do TypeScript. Ele define como o código será compilado e quais regras serão aplicadas.
📌 Criando um tsconfig.json
Execute no terminal:
tsc --init
Isso gera um arquivo tsconfig.json com várias configurações comentadas.
📌 Exemplo de tsconfig.json Básico
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
| Opção | Descrição |
|---|---|
| "target": "ES6" | Compila TypeScript para JavaScript ES6. |
| "module": "CommonJS" | Usa módulos no estilo Node.js. |
| "outDir": "./dist" | Define a pasta onde o código compilado será salvo. |
| "rootDir": "./src" | Define a pasta onde o código TypeScript está localizado. |
| "strict": true | Ativa verificações rigorosas de tipo. |
| "noImplicitAny": true | Evita variáveis sem tipo explícito. |
| "esModuleInterop": true | Permite importações de módulos ES6. |
| "include": ["src"] | Compila apenas arquivos dentro da pasta src. |
| "exclude": ["node_modules"] | Exclui node_modules da compilação. |
✅ Personalizando o tsconfig.json
Se estiver usando React, altere "module" para "ESNext" e "jsx" para "react".
{
"compilerOptions": {
"module": "ESNext",
"jsx": "react"
}
}
6.2 tsc (Compilador TypeScript)
O TypeScript Compiler (tsc) é a ferramenta que converte TypeScript em JavaScript.
📌 Compilar um arquivo manualmente
tsc meuArquivo.ts
Isso gera um meuArquivo.js com o código JavaScript equivalente.
📌 Compilar todo o projeto baseado no tsconfig.json
tsc
Isso compila todos os arquivos .ts conforme definido no tsconfig.json.
📌 Compilar e assistir mudanças automaticamente
tsc --watch
Isso recompila automaticamente os arquivos ao serem alterados.
6.3 ESLint e Prettier (Linting e Formatação)
ESLint (Análise de Código Estático)
O ESLint ajuda a identificar erros e padrões ruins no código.
📌 Instalando o ESLint no projeto
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
📌 Criando um arquivo de configuração .eslintrc.json
{
"parser": "@typescript-eslint/parser",
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"],
"@typescript-eslint/no-explicit-any": "warn"
}
}
📌 Rodando o ESLint no código
npx eslint src/**/*.ts
Prettier (Formatação de Código)
O Prettier formata o código automaticamente. Ele é útil junto com o ESLint.
📌 Instalando o Prettier
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
📌 Criando um arquivo de configuração .prettierrc
{
"semi": true,
"singleQuote": false,
"tabWidth": 2
}
📌 Formatando código com Prettier
npx prettier --write src/**/*.ts
Resumo
| Ferramenta | Função |
|---|---|
| tsconfig.json | Configuração do compilador TypeScript |
| tsc (TypeScript Compiler) | Transpila código TypeScript para JavaScript |
| ESLint | Detecta erros e melhora a qualidade do código |
| Prettier | Formata o código automaticamente |
Conclusão
Com essas ferramentas, você garante que seu projeto TypeScript seja bem configurado, compilado corretamente e siga padrões de qualidade. 🚀
7. Integração com Frameworks no TypeScript
7.1 TypeScript com Node.js
O Node.js é uma plataforma para execução de JavaScript no backend. O TypeScript funciona com o Node.js, mas como o Node não entende TypeScript diretamente, precisamos de:
- Compilar TypeScript para JavaScript usando tsc.
- Adicionar as tipagens do Node.js com @types/node.
Configurando um projeto TypeScript no Node.js
📌 1. Criar um novo projeto
mkdir meu-projeto-node && cd meu-projeto-node
npm init -y
📌 2. Instalar o TypeScript e as tipagens do Node.js
npm install --save-dev typescript ts-node @types/node
📌 3. Criar um tsconfig.json
tsc --init
📌 4. Criar um arquivo server.ts
import http from "http";
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Olá, TypeScript com Node.js!");
});
server.listen(3000, () => console.log("Servidor rodando em http://localhost:3000"));
📌 5. Executar o servidor com ts-node
npx ts-node server.ts
✅ Destaques:
- @types/node fornece tipagens para as APIs do Node.js.
- ts-node permite executar TypeScript diretamente, sem precisar compilar antes.
7.2 TypeScript com React
O React tem suporte nativo ao TypeScript, usando arquivos .tsx para tipagem de componentes.
Criando um projeto React com TypeScript
📌 1. Criar um novo projeto React com TypeScript
npx create-react-app meu-app --template typescript
📌 2. Criar um componente com tipagem (App.tsx)
import React from "react";
type Props = {
nome: string;
};
const Saudacao: React.FC<Props> = ({ nome }) => {
return <h1>Olá, {nome}!</h1>;
};
const App: React.FC = () => {
return <Saudacao nome="Alice" />;
};
export default App;
✅ Destaques:
- O React.FC<T> define que Saudacao é um componente funcional com props tipadas.
- O nome tem tipagem explícita (string), reduzindo erros.
Tipagem de Estados e Eventos no React
📌 Gerenciando estado com useState
import React, { useState } from "react";
const Contador: React.FC = () => {
const [contador, setContador] = useState<number>(0);
return (
<div>
<p>Valor: {contador}</p>
<button onClick={() => setContador(contador + 1)}>Incrementar</button>
</div>
);
};
export default Contador;
📌 Tipagem de eventos (onChange, onClick)
const InputTexto: React.FC = () => {
const [texto, setTexto] = useState<string>("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setTexto(event.target.value);
};
return <input type="text" value={texto} onChange={handleChange} />;
};
| Destaque | Descrição |
|---|---|
| useState<number>(0) | Garante que o estado só aceite números. |
| onChange={handleChange} | handleChange recebe um evento tipado corretamente (ChangeEvent<HTMLInputElement>). |
7.3 TypeScript com Angular
O Angular foi criado pelo Google e tem suporte nativo ao TypeScript. Na verdade, o Angular usa TypeScript como linguagem principal.
Criando um projeto Angular com TypeScript
📌 1. Instalar o Angular CLI
npm install -g @angular/cli
📌 2. Criar um novo projeto Angular
ng new meu-app-angular
cd meu-app-angular
ng serve
✅ O Angular já usa TypeScript por padrão, então não é necessário configurá-lo manualmente.
Tipagem no Angular
📌 Criando um (Component) com tipagem (app.component.ts)
import { Component } from "@angular/core";
@Component({
selector: "app-root",
template: "<h1>Olá, {{ nome }}</h1>",
})
export class AppComponent {
nome: string = "Mundo";
}
📌 Tipando um serviço (usuario.service.ts)
import { Injectable } from "@angular/core";
interface Usuario {
id: number;
nome: string;
}
@Injectable({
providedIn: "root",
})
export class UsuarioService {
private usuarios: Usuario[] = [
{ id: 1, nome: "Alice" },
{ id: 2, nome: "Bob" },
];
getUsuarios(): Usuario[] {
return this.usuarios;
}
}
| Destaque | Descrição |
|---|---|
| @Component() | Define um componente Angular. |
| @Injectable() | Define um serviço Angular. |
| interface Usuario | Melhora a segurança do código. |
Comparação entre Node.js, React e Angular com TypeScript
| Framework | Integração com TypeScript | Exemplo de uso |
|---|---|---|
| Node.js | Usa @types/node para APIs | Servidor HTTP, APIs REST |
| React | Usa .tsx, React.FC<T> | Componentes, hooks, eventos |
| Angular | Baseado 100% em TypeScript | Componentes, serviços, injeção de dependências |
Conclusão
O TypeScript traz grandes benefícios ao trabalhar com frameworks modernos:
- Node.js: Tipagem para APIs e maior segurança no backend.
- React: Melhor suporte a componentes e eventos com
.tsx. - Angular: Integração total, pois é construído sobre TypeScript.
Aprenda um CRUD
Aqui está um exemplo de um CRUD simples para cadastrar alunos:
HTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1> Crud para cadastrar anluos</h1>
<form id="aluno-form">
<input type="text" id="nome" placeholder="nome do aluno" required>
<button type="submit">Adicionar aluno</button>
</form>
<table>
<thead>
<tr>
<th>Nome</th>
<th>Ação</th>
</tr>
</thead>
<tbody id="alunos-tabela">
<!--os dados serão inseridos aqui-->
</tbody>
</table>
<script src="script.js"></script>
</body>
</html>
CSS
/* Reset básico */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #f9f9f9;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #333;
margin-bottom: 20px;
}
form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
input[type="text"] {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
width: 200px;
}
button {
padding: 10px 15px;
border: none;
background-color: #000000;
color: white;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #6b6b6b;
}
table {
width: 80%;
max-width: 600px;
border-collapse: collapse;
margin-top: 10px;
}
thead {
background-color: #000000;
color: white;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
td button {
padding: 5px 10px;
font-size: 14px;
background-color: #28a745;
border: none;
color: white;
border-radius: 3px;
cursor: pointer;
transition: background-color 0.3s;
}
td button:nth-child(2) {
background-color: #dc3545;
}
td button:hover {
opacity: 0.8;
}
JavaScript
const formulario = document.getElementById ("aluno-form");
const tabela = document.getElementById("alunos-tabela");
let alunos = []; // Armazena os dados dos alunos
formulario.addEventListener("submit", (evento)=> {
evento.preventDefault();
const nomeInput = document.getElementById("nome");
const nomeAluno = nomeInput.value.trim();
if(nomeAluno){
// Adicionar o aluno na lista e renderizar
adicionarAluno(nomeAluno);
nomeInput.value = ""; // Limpa o campo após adicionar
}
});
function adicionarAluno(nome) {
const novoAluno = {id: Date.now(), nome: nome}; // cria o aluno com ID unico
alunos.push(novoAluno);
atualizarTabela();
}
function atualizarTabela(){
tabela.innerHTML = ""; // Limpa a tabela antes de renderizar
alunos.forEach(aluno => {
const linha = document.createElement("tr");
linha.innerHTML = `
<td>${aluno.nome}</td>
<td>
<button onclick="editarAluno(${aluno.id})">Editar</button>
<button onclick="deletarAluno(${aluno.id})">Excluir</button>
</td>
`;
tabela.appendChild(linha);
});
}
function editarAluno(id){
const aluno = alunos.find(aluno => aluno.id === id);
if(aluno){
const novoNome = prompt("Digite o novo nome do aluno", aluno.nome);
if(novoNome && novoNome.trim() !== ""){
aluno.nome = novoNome.trim();
atualizarTabela();
}
}
}
function deletarAluno(id){
alunos = alunos.filter(aluno => aluno.id !== id);
atualizarTabela();
}
