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 void també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:

  1. tsconfig.json – Configuração do compilador TypeScript.
  2. tsc (TypeScript Compiler) – Transpila TypeScript para JavaScript.
  3. 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:

  1. Compilar TypeScript para JavaScript usando tsc.
  2. 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();
}

Comandos TypeScript e o que fazem

Comando / Sintaxe Descrição
let nome: stringDeclaração de variável com tipo string
const idade: numberConstante com tipo numérico
let ativo: booleanBooleano verdadeiro ou falso
number[]Array de números
[string, number]Tupla com tipos fixos
enum Status { Ativo, Inativo }Enumeração de estados fixos
function soma(a: number, b: number): numberFunção com tipos definidos
: voidFunção que não retorna valor
: anyTipo genérico (qualquer valor)
type User = {}Tipo personalizado (alias)
interface User {}Interface com estrutura de objeto
readonlyPropriedade somente leitura
optional?:Propriedade opcional
as stringType casting (conversão de tipo)
typeof variávelRetorna o tipo da variável
keyof TipoRetorna as chaves de um tipo
Record<Chave, Valor>Objeto com chaves e valores dinâmicos
Partial<T>Todos os campos opcionais
Required<T>Todos os campos obrigatórios
Pick<T, 'a' | 'b'>Seleciona algumas props
Omit<T, 'a'>Remove uma prop de T
extendsHerança entre tipos ou classes
implementsClasse implementando interface
abstract classClasse base abstrata
function <T>(arg: T): TFunção genérica
T extends U ? X : YTipo condicional
neverFunção que nunca retorna (ex: erro)
unknownTipo desconhecido (seguro)
as constValor literal e imutável
namespace MeuNS {}Agrupamento de código em namespaces
declare varDeclara uma variável externa (ambient)
export / importTrabalhar com módulos