Seu primeiro programa
por Ellery BlackwoodEntenda 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.
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) eboolean. - Template literals usam crase e
${}para encaixar valores no texto. node arquivo.tsroda o código sem checar tipos;tsc --noEmitfaz a checagem.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Olá, mundo com tipos
// 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
// 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
// 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.
- Usar anotações
string,numberebooleanem constantes declaradas comconst. - Calcular a idade da obra com uma subtração entre
anoAtualeano. - Imprimir as cinco linhas com
console.loge template literals. - A saída deve ser exatamente igual à esperada.
// 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}`);
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
- As duas primeiras constantes guardam texto, por isso recebem a anotação
string; aspas simples são o estilo mais comum em TypeScript. anoeanoAtualsãonumber. Guardar o ano atual numa constante evita um "número mágico" perdido no meio doconsole.log.disponiveléboolean: só aceitatrueoufalse, que é exatamente a informação "está na estante ou não".- Cada
console.logimprime uma linha e já pula para a seguinte, por isso não é preciso escrever\n. - Os template literals (crase) encaixam o valor de cada constante no texto com
${}. - A linha da idade calcula
anoAtual - anodentro 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 literalmenteAno: ${ano}. Só a crase interpreta o${}. - Guardar o ano como texto:
const ano: string = '1899'e depoisanoAtual - anodá erro notsc(TS2363: o lado direito de uma operação aritmética precisa ser número). Usenumber. - 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.
- 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
booleanfeita com>=.
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}`);
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
- As notas ficam em três constantes
number. Em TypeScript não há tipo separado para decimal:7e8.5são ambosnumber. (nota1 + nota2 + nota3) / 3soma primeiro por causa dos parênteses e depois divide; o resultado é7.1666....media >= 7é uma comparação, e toda comparação devolve umboolean. Por issoaprovadapode ser anotada comoboolean.nota1aparece como7e não7.0: o JavaScript imprime o número sem zeros desnecessários.media.toFixed(1)devolve uma string com uma casa decimal, arredondada:7.1666...vira7.2.- A última linha imprime o
booleandireto, que aparece comotrueno 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 / 3dá17.5, porque a divisão tem precedência maior que a soma. - Comparar o texto formatado:
media.toFixed(1) >= 7dá erro notsc, pois comparastringcomnumber. Compare a média numérica. - Anotar
const media: string = (nota1 + nota2 + nota3) / 3gera 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.
- Criar
function pontos(vitorias: number, empates: number): number. - Criar
function linha(time: string, total: number): stringque alinha o nome compadEnd(10)e os pontos compadStart(3). - Decidir o líder com
if/else if/elsecomparando 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.
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');
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
pontosrecebe doisnumbere devolve umnumber. A anotação de retorno): numberfaz otscreclamar se algum caminho da função esquecer oreturn.linharecebe o nome e o total já calculado e devolve umastring.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.String(total).padStart(3)converte o número em texto e o completa à esquerda;padStarté método destring, não denumber.- Os pontos de cada time ficam em constantes:
pontos(5, 2)dá17,pontos(4, 4)dá16epontos(3, 1)dá10. '-'.repeat(20)gera o separador uma vez só, guardado numa constante usada duas vezes.let lider: string;declara a variável sem valor inicial. Otscconfere que todos os ramos doifatribuem um valor antes doconsole.log.- O primeiro teste usa
&¶ exigir que os Dragões tenham pelo menos tantos pontos quanto cada rival; se falhar, oelse ifdecide 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
padStartdireto no número:total.padStart(3)dá erro notsc("Property 'padStart' does not exist on type 'number'") e erro em tempo de execução no Node. Converta comString(total)antes. - Usar
const liderdentro de cada ramo doif: a constante só existe dentro do bloco, e oconsole.logde fora dá erro de nome não encontrado. Declarelet lider: string;antes doif. - Esquecer o
else: com sóifeelse if, otscacusa queliderpode 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