Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

✦   Lição

Seu primeiro programa

TypeScript é JavaScript com tipos. Um programa TypeScript é um arquivo .ts com instruções que rodam de cima para baixo; a mais básica é console.log, que escreve uma linha na saída.

TypeScript Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
TypeScript / Fundamentos

Seu primeiro programa

por Ellery Blackwood
Iniciante

Entenda o conceito

TypeScript é JavaScript com tipos. Um programa TypeScript é um arquivo .ts com instruções que rodam de cima para baixo; a mais básica é console.log, que escreve uma linha na saída.

A novidade em relação ao JavaScript são as anotações de tipo: depois do nome de uma variável vem : e o tipo, como em const preco: number = 10;. Os tipos mais usados no começo são string (texto), number (números inteiros e decimais) e boolean (true ou false). Quando o valor deixa o tipo óbvio, você pode omitir a anotação e o TypeScript infere o tipo sozinho.

Para rodar, basta node arquivo.ts no Node atual: ele apaga os tipos e executa o JavaScript que sobra, sem conferi-los. Quem confere os tipos é o compilador tsc (npx --package typescript tsc --noEmit arquivo.ts), que aponta o erro antes de o programa rodar.

↳ Pontos-chave
  • console.log(valor) imprime o valor e pula para a próxima linha.
  • A anotação vem depois do nome: const nome: string = 'Ana';.
  • Os tipos básicos são string, number (inteiro ou decimal) e boolean.
  • Template literals usam crase e ${} para encaixar valores no texto.
  • node arquivo.ts roda o código sem checar tipos; tsc --noEmit faz a checagem.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Olá, mundo com tipos

ola.ts
// Seu primeiro programa em TypeScript: uma mensagem de boas-vindas da loja.
// Rode com: node ola.ts

// Cada constante tem um tipo depois dos dois-pontos.
const loja: string = 'Mercadinho da Esquina';
const anoDeAbertura: number = 2015;
const abertoHoje: boolean = true;

// console.log escreve uma linha na saída.
console.log('Olá, mundo!');
console.log('Bem-vindo ao ' + loja + '.');

// Template literal: crase e ${} para encaixar valores no texto.
console.log(`Estamos abertos desde ${anoDeAbertura}.`);
console.log(`Aberto hoje? ${abertoHoje}`);

// Uma conta simples também vira texto.
const anoAtual: number = 2026;
console.log(`São ${anoAtual - anoDeAbertura} anos de história.`);

O programa declara três constantes, uma de cada tipo básico (string, number e boolean), e imprime cinco linhas com console.log. A segunda linha junta textos com +; as seguintes usam template literals, que são mais legíveis quando há valores no meio da frase.

A última linha mostra que dentro de ${} cabe qualquer expressão, inclusive uma conta. Os tipos não mudam a saída: eles servem para o tsc avisar se você, por engano, guardar um texto onde deveria haver um número.

02Ajustando as porções de uma receita

receita.ts
// Ajustando uma receita: tipos anotados e tipos inferidos.

const receita: string = 'Bolo de cenoura';
const porcoesOriginais: number = 8;
const farinhaGramas: number = 240;
const ovos: number = 3;

// Sem anotação, o TypeScript infere o tipo pelo valor: aqui, number.
const porcoesDesejadas = 12;

// Fator de escala: quanto a receita cresce.
const fator = porcoesDesejadas / porcoesOriginais;

console.log(`Receita: ${receita}`);
console.log(`Porções: ${porcoesOriginais} -> ${porcoesDesejadas}`);
console.log(`Fator: ${fator}`);
console.log(`Farinha: ${farinhaGramas * fator} g`);
// Math.ceil arredonda para cima: não dá para usar meio ovo.
console.log(`Ovos: ${Math.ceil(ovos * fator)}`);

// A linha abaixo não passa no tsc: porcoesDesejadas é number, não string.
// const texto: string = porcoesDesejadas;

Aqui aparecem os dois jeitos de ter um tipo: anotado (const ovos: number = 3) e inferido (const porcoesDesejadas = 12, que o TypeScript entende como number pelo valor). Nos dois casos o tipo fica fixo: tentar guardar esse número numa variável string, como na linha comentada no fim, é erro de compilação no tsc.

O exemplo também mostra que number serve para inteiros e decimais (o fator é 1.5) e usa Math.ceil para arredondar a quantidade de ovos para cima, já que não existe meio ovo na receita.

03Carrinho com funções tipadas

carrinho.ts
// Um carrinho pequeno: funções com parâmetros e retorno tipados.

// Recebe preço e quantidade (number) e devolve o subtotal (number).
function subtotal(preco: number, quantidade: number): number {
  return preco * quantidade;
}

// Formata um valor em reais com duas casas decimais.
function emReais(valor: number): string {
  return `R$ ${valor.toFixed(2)}`;
}

const caderno = subtotal(12.5, 3);
const caneta = subtotal(2.75, 4);
const mochila = subtotal(89.9, 1);
const total = caderno + caneta + mochila;

console.log(`Caderno x3: ${emReais(caderno)}`);
console.log(`Caneta x4:  ${emReais(caneta)}`);
console.log(`Mochila x1: ${emReais(mochila)}`);
console.log('-'.repeat(22));
console.log(`Total:      ${emReais(total)}`);

// Com tipos, o tsc avisa antes de rodar se você passar texto no lugar de número:
// subtotal('12.5', 3); // erro: string não é atribuível a number

As funções recebem tipos nos parâmetros (preco: number) e no retorno (): number {). Assim, quem lê sabe o que entra e o que sai, e o tsc recusa uma chamada como subtotal('12.5', 3), que em JavaScript puro passaria e daria um resultado estranho.

A função emReais usa toFixed(2) para mostrar sempre duas casas decimais, o jeito comum de exibir dinheiro. Separar o cálculo (subtotal) da formatação (emReais) deixa cada função curta e fácil de testar.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Ficha de um livro do acervoFácil

Escreva um programa que guarde os dados de um livro da biblioteca em constantes com tipo explícito e imprima a ficha abaixo. A idade da obra deve ser calculada a partir do ano atual (2026), não escrita à mão.

↳ Requisitos
  • Usar anotações string, number e boolean em constantes declaradas com const.
  • Calcular a idade da obra com uma subtração entre anoAtual e ano.
  • Imprimir as cinco linhas com console.log e template literals.
  • A saída deve ser exatamente igual à esperada.
código inicial
// Complete as constantes com o tipo certo e imprima a ficha.
const titulo: string = 'Dom Casmurro';
// const autor ...
// const ano ...
// const disponivel ...
const anoAtual: number = 2026;

console.log(`Título: ${titulo}`);
saída esperada
Título: Dom Casmurro
Autor: Machado de Assis
Ano: 1899
Idade da obra: 127 anos
Disponível: true
Ver dica

Dentro de ${} cabe uma conta inteira, como ${anoAtual - ano}.

Ver resposta
// Ficha de um livro do acervo, com tipos explícitos.
const titulo: string = 'Dom Casmurro';
const autor: string = 'Machado de Assis';
const ano: number = 1899;
const disponivel: boolean = true;
const anoAtual: number = 2026;

// Cada console.log imprime uma linha da ficha.
console.log(`Título: ${titulo}`);
console.log(`Autor: ${autor}`);
console.log(`Ano: ${ano}`);
console.log(`Idade da obra: ${anoAtual - ano} anos`);
console.log(`Disponível: ${disponivel}`);

Passo a passo

  1. As duas primeiras constantes guardam texto, por isso recebem a anotação string; aspas simples são o estilo mais comum em TypeScript.
  2. ano e anoAtual são number. Guardar o ano atual numa constante evita um "número mágico" perdido no meio do console.log.
  3. disponivel é boolean: só aceita true ou false, que é exatamente a informação "está na estante ou não".
  4. Cada console.log imprime uma linha e já pula para a seguinte, por isso não é preciso escrever \n.
  5. Os template literals (crase) encaixam o valor de cada constante no texto com ${}.
  6. A linha da idade calcula anoAtual - ano dentro do ${}, então o resultado (127) acompanha qualquer mudança nas constantes.

Por que funciona

O programa roda de cima para baixo: primeiro declara os dados, depois imprime. As anotações não mudam o que é impresso, mas documentam o que cada constante guarda e deixam o tsc recusar enganos, como const ano: number = '1899'. Ao rodar com node ficha.ts, os tipos são apagados e sobra o JavaScript que gera a ficha.

Erros comuns

  • Usar aspas comuns no lugar da crase: console.log('Ano: ${ano}') imprime literalmente Ano: ${ano}. Só a crase interpreta o ${}.
  • Guardar o ano como texto: const ano: string = '1899' e depois anoAtual - ano dá erro no tsc (TS2363: o lado direito de uma operação aritmética precisa ser número). Use number.
  • Escrever a idade à mão (Idade da obra: 127 anos): funciona hoje, mas fica errada no ano que vem e descumpre o requisito.

Outra forma de resolver

Como os valores deixam o tipo óbvio, dá para omitir as anotações (const ano = 1899;) e deixar o TypeScript inferir. É o estilo preferido no dia a dia quando o valor é literal; aqui as anotações ficam explícitas porque o exercício pede para praticá-las.

Saída esperada

Título: Dom Casmurro
Autor: Machado de Assis
Ano: 1899
Idade da obra: 127 anos
Disponível: true

02Média do boletimMédio

Calcule a média de três notas de uma aluna e diga se ela foi aprovada (média maior ou igual a 7). Mostre a média com uma casa decimal.

↳ Requisitos
  • Guardar as notas em constantes anotadas como number.
  • Calcular a média com parênteses em volta da soma.
  • Exibir a média com toFixed(1).
  • Guardar o resultado da aprovação numa constante boolean feita com >=.
código inicial
const aluna: string = 'Beatriz';
const nota1: number = 7;
const nota2: number = 8.5;
const nota3: number = 6;

// calcule a média e se a aluna foi aprovada

console.log(`Aluna: ${aluna}`);
saída esperada
Aluna: Beatriz
Notas: 7, 8.5, 6
Média: 7.2
Aprovada: true
Ver dica

Sem parênteses, a divisão acontece antes da soma: só a última nota seria dividida por 3.

Ver resposta
// Média de uma aluna, com uma casa decimal.
const aluna: string = 'Beatriz';
const nota1: number = 7;
const nota2: number = 8.5;
const nota3: number = 6;

// Os parênteses fazem a soma acontecer antes da divisão.
const media: number = (nota1 + nota2 + nota3) / 3;
// Comparação devolve boolean: true ou false.
const aprovada: boolean = media >= 7;

console.log(`Aluna: ${aluna}`);
console.log(`Notas: ${nota1}, ${nota2}, ${nota3}`);
// toFixed(1) devolve uma string com uma casa decimal, arredondada.
console.log(`Média: ${media.toFixed(1)}`);
console.log(`Aprovada: ${aprovada}`);

Passo a passo

  1. As notas ficam em três constantes number. Em TypeScript não há tipo separado para decimal: 7 e 8.5 são ambos number.
  2. (nota1 + nota2 + nota3) / 3 soma primeiro por causa dos parênteses e depois divide; o resultado é 7.1666....
  3. media >= 7 é uma comparação, e toda comparação devolve um boolean. Por isso aprovada pode ser anotada como boolean.
  4. nota1 aparece como 7 e não 7.0: o JavaScript imprime o número sem zeros desnecessários.
  5. media.toFixed(1) devolve uma string com uma casa decimal, arredondada: 7.1666... vira 7.2.
  6. A última linha imprime o boolean direto, que aparece como true no texto.

Por que funciona

Os tipos garantem que só números entram na conta: se uma das notas fosse a string '8.5', o + faria concatenação de texto e a média sairia errada, mas o tsc recusaria a anotação number para esse valor. O arredondamento fica só na hora de exibir, e a comparação usa o valor exato da média.

Erros comuns

  • Esquecer os parênteses: nota1 + nota2 + nota3 / 3 dá 17.5, porque a divisão tem precedência maior que a soma.
  • Comparar o texto formatado: media.toFixed(1) >= 7 dá erro no tsc, pois compara string com number. Compare a média numérica.
  • Anotar const media: string = (nota1 + nota2 + nota3) / 3 gera erro de tipo: o resultado da conta é number.

Outra forma de resolver

Dá para arredondar com Math.round(media * 10) / 10, que devolve um number (útil se o valor ainda for usado em contas). Para só exibir, toFixed(1) é mais simples e sempre mostra a casa decimal, inclusive em 7.0.

Saída esperada

Aluna: Beatriz
Notas: 7, 8.5, 6
Média: 7.2
Aprovada: true

03Placar do campeonatoDesafio

Monte o placar de um campeonato com três times, em que vitória vale 3 pontos e empate vale 1. Use uma função para calcular os pontos, outra para formatar cada linha alinhada e decida o líder comparando os pontos.

↳ Requisitos
  • Criar function pontos(vitorias: number, empates: number): number.
  • Criar function linha(time: string, total: number): string que alinha o nome com padEnd(10) e os pontos com padStart(3).
  • Decidir o líder com if/else if/else comparando os pontos, sem escrever o nome à mão.
  • Dados: Dragões 5 vitórias e 2 empates, Tigres 4 e 4, Falcões 3 e 1; a saída deve ser exatamente a esperada.
código inicial
function pontos(vitorias: number, empates: number): number {
  // vitória vale 3, empate vale 1
  return 0;
}

function linha(time: string, total: number): string {
  // alinhe o nome em 10 colunas e os pontos em 3
  return '';
}

console.log('Placar do campeonato');
saída esperada
Placar do campeonato
--------------------
Dragões    17 pts
Tigres     16 pts
Falcões    10 pts
--------------------
Líder: Dragões
Ver dica

padStart só existe em texto: converta os pontos com String(total) antes de alinhar.

Ver resposta
// Placar do campeonato: vitória vale 3 pontos, empate vale 1.
function pontos(vitorias: number, empates: number): number {
  return vitorias * 3 + empates;
}

// Monta uma linha alinhada: nome com 10 colunas e pontos com 3.
function linha(time: string, total: number): string {
  return `${time.padEnd(10)}${String(total).padStart(3)} pts`;
}

const dragoes: number = pontos(5, 2);
const tigres: number = pontos(4, 4);
const falcoes: number = pontos(3, 1);

const separador: string = '-'.repeat(20);
console.log('Placar do campeonato');
console.log(separador);
console.log(linha('Dragões', dragoes));
console.log(linha('Tigres', tigres));
console.log(linha('Falcões', falcoes));
console.log(separador);

// Decide o líder comparando os pontos (o primeiro que passa no teste vence).
let lider: string;
if (dragoes >= tigres && dragoes >= falcoes) {
  lider = 'Dragões';
} else if (tigres >= falcoes) {
  lider = 'Tigres';
} else {
  lider = 'Falcões';
}
console.log(`Líder: ${lider}`);

Passo a passo

  1. pontos recebe dois number e devolve um number. A anotação de retorno ): number faz o tsc reclamar se algum caminho da função esquecer o return.
  2. linha recebe o nome e o total já calculado e devolve uma string. time.padEnd(10) completa o nome com espaços à direita até 10 caracteres, e assim todas as colunas de pontos começam no mesmo lugar.
  3. String(total).padStart(3) converte o número em texto e o completa à esquerda; padStart é método de string, não de number.
  4. Os pontos de cada time ficam em constantes: pontos(5, 2) dá 17, pontos(4, 4) dá 16 e pontos(3, 1) dá 10.
  5. '-'.repeat(20) gera o separador uma vez só, guardado numa constante usada duas vezes.
  6. let lider: string; declara a variável sem valor inicial. O tsc confere que todos os ramos do if atribuem um valor antes do console.log.
  7. O primeiro teste usa && para exigir que os Dragões tenham pelo menos tantos pontos quanto cada rival; se falhar, o else if decide entre os outros dois.

Por que funciona

O programa separa calcular (pontos), formatar (linha) e decidir (o if). As assinaturas tipadas deixam claro o contrato de cada função: trocar a ordem dos argumentos em linha(17, 'Dragões') é erro de compilação, não uma linha torta descoberta só na saída. Como o líder vem da comparação, mudar os resultados dos jogos muda o líder sem tocar no resto do código.

O >= nos testes resolve empates a favor do time que aparece primeiro, o que mantém o resultado previsível. A saída é sempre a mesma porque não há nada aleatório: só contas e comparações sobre constantes.

Erros comuns

  • Chamar padStart direto no número: total.padStart(3) dá erro no tsc ("Property 'padStart' does not exist on type 'number'") e erro em tempo de execução no Node. Converta com String(total) antes.
  • Usar const lider dentro de cada ramo do if: a constante só existe dentro do bloco, e o console.log de fora dá erro de nome não encontrado. Declare let lider: string; antes do if.
  • Esquecer o else: com só if e else if, o tsc acusa que lider pode ser usado antes de receber valor ("Variable 'lider' is used before being assigned").
  • Somar vitórias e empates sem peso (vitorias + empates): o código roda, mas o placar fica errado. Multiplique as vitórias por 3.

Outra forma de resolver

Com o operador ternário, a decisão cabe numa expressão e permite const: const lider = dragoes >= tigres && dragoes >= falcoes ? 'Dragões' : tigres >= falcoes ? 'Tigres' : 'Falcões';. Fica mais curto, mas ternários encadeados ficam difíceis de ler; com mais times, o caminho é guardar os times numa lista e ordenar, assunto de lições futuras.

Saída esperada

Placar do campeonato
--------------------
Dragões    17 pts
Tigres     16 pts
Falcões    10 pts
--------------------
Líder: Dragões

Últimas lições

Ver o arquivo completo →