Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Tipos básicos em TypeScript: string, number e mais

Aprenda inferência, anotações, arrays, objetos, unions, literals e unknown com exemplos executáveis e erros que o compilador encontra antes do Node.

Rodolfo Mori5 min de leitura

Os tipos básicos do TypeScript descrevem os valores que seu JavaScript já usa: texto é string, número é number, verdadeiro ou falso é boolean, listas são arrays e objetos têm propriedades com tipos próprios. A partir dessas peças, você combina alternativas com unions e protege dados desconhecidos com unknown.

Nesta lição, a gente vai montar o cadastro de um produto por partes. Você verá o que o compilador infere sozinho, onde uma anotação acrescenta informação e como um erro muda quando o contrato fica mais preciso. Se ainda não tem um projeto rodando, faça antes a instalação do TypeScript.

Etiquetas de estoque: o modelo mental dos tipos

Imagine um estoque em que cada prateleira tem uma etiqueta: “cabos”, “teclados”, “itens frágeis”. A etiqueta não cria o produto nem muda o que existe na caixa. Ela registra que tipo de item pode ocupar aquele lugar e permite perceber um engano antes de o pedido ser separado.

No TypeScript, o valor é o produto, o tipo é a etiqueta e o compilador confere a compatibilidade. Uma anotação como preco: number não converte texto; ela declara que apenas números cabem ali. O limite da analogia é que um valor pode satisfazer várias descrições estruturais ao mesmo tempo, e o compilador consegue deduzir etiquetas sem você escrevê-las.

O comportamento técnico volta ao centro: tipos existem para análise e são apagados antes da execução. Quem roda dist/index.js é o Node, usando valores de JavaScript, não etiquetas do TypeScript.

Deixe a inferência ler o valor evidente

Inferência de tipos é a capacidade de deduzir o tipo pelo valor e pelo contexto. Passe o cursor sobre estas constantes no editor:

ts
const nome = 'Mouse vertical';
const preco = 189.9;
const disponivel = true;

console.log(typeof nome, typeof preco, typeof disponivel);
string number boolean

TypeScript infere nome como o literal 'Mouse vertical', preco como o literal 189.9 e disponivel como true, porque const não será reatribuído. No uso cotidiano, esses valores continuam compatíveis com string, number e boolean. Escrever as três anotações repetiria o que já está claro.

Com let, o compilador normalmente amplia o tipo para permitir outra atribuição da mesma família:

ts
let estoque = 10;
estoque = 8;

console.log(estoque);
8

Troque a segunda linha por estoque = 'oito' e rode npx tsc --noEmit:

ts
let estoque = 10;
estoque = 'oito';
error TS2322: Type 'string' is not assignable to type 'number'.

O compilador inferiu number na primeira atribuição e manteve esse contrato nas seguintes. O erro não depende de uma anotação explícita; inferência também gera uma regra verificável.

Anote quando o começo não conta a história inteira

Uma variável que começa vazia e recebe um valor depois precisa de contexto. Sem ele, let codigo; tende a perder precisão. Declare o conjunto permitido:

ts
let codigoSelecionado: string | null = null;

codigoSelecionado = 'PROD-42';
console.log(codigoSelecionado);
PROD-42

O sinal | cria uma union type, traduzida como “um tipo ou outro”. A variável aceita ausência intencional (null) e depois um texto. Ela não aceita um número. Esse é um caso em que a anotação acrescenta informação que o valor inicial não consegue contar.

Parâmetros de função também precisam de anotação no modo estrito, porque o compilador não tem uma chamada única para deduzir a intenção:

ts
function aplicarDesconto(preco: number, percentual: number): number {
  return preco - preco * percentual;
}

console.log(aplicarDesconto(200, 0.15).toFixed(2));
170.00

: number depois dos parênteses descreve o retorno. Se uma manutenção trocar o retorno por `R$ ${preco}`, o erro aparece dentro da função, perto da causa, e não apenas em cada lugar que esperava fazer uma conta.

Arrays dizem qual item pode entrar

string[] é um array de strings; Array<string> é uma escrita equivalente. Escolha uma convenção e mantenha consistência. Aqui o carrinho guarda objetos:

ts
type Item = {
  nome: string;
  preco: number;
};

const itens: Item[] = [
  { nome: 'Mouse', preco: 189.9 },
  { nome: 'Teclado', preco: 250 },
];

console.log(itens.map((item) => item.nome).join(', '));
Mouse, Teclado

O tipo se propaga para o callback de map: item.nome oferece operações de string e item.preco oferece operações de número. Tente inserir { nome: 'Monitor', preco: '900' }; o compilador aponta a propriedade incompatível antes de o valor contaminar a soma.

Com noUncheckedIndexedAccess, ler itens[0] devolve Item | undefined, porque o array pode estar vazio. Isso não é burocracia: é a diferença entre uma posição possível e um item garantido. Você pode usar optional chaining ou testar a existência antes de acessar.

Objetos descrevem propriedades obrigatórias e opcionais

Uma propriedade com ? é opcional. Ao ler descricao, o tipo será string | undefined, porque a chave pode faltar:

ts
type Produto = {
  id: number;
  nome: string;
  descricao?: string;
};

const produto: Produto = {
  id: 42,
  nome: 'Mouse vertical',
};

console.log(produto.descricao?.toUpperCase() ?? 'SEM DESCRIÇÃO');
SEM DESCRIÇÃO

?. interrompe o acesso se o lado esquerdo for null ou undefined; ?? fornece o texto alternativo. Essa combinação é JavaScript em execução, enquanto o tipo opcional fez o editor exigir o cuidado. Se quiser aprofundar a operação, há uma lição de optional chaining.

Não marque tudo como opcional para “parar de dar erro”. Se todo produto precisa de nome para aparecer no catálogo, nome: string deve continuar obrigatório. Um contrato útil diferencia ausência permitida de dado esquecido.

Literal types transformam texto solto em estados conhecidos

O tipo string aceita infinitos textos. Quando o domínio conhece opções fechadas, use literal types numa union:

ts
type StatusEstoque = 'disponivel' | 'baixo' | 'esgotado';

function aviso(status: StatusEstoque): string {
  if (status === 'esgotado') return 'Repor produto';
  if (status === 'baixo') return 'Planejar compra';
  return 'Estoque normal';
}

console.log(aviso('baixo'));
Planejar compra

Uma chamada aviso('acabando') reproduz TS2345, porque esse texto não faz parte do conjunto. A vantagem não é escrever menos caracteres; é centralizar o vocabulário válido e ganhar autocomplete. Se uma quarta situação entrar no negócio, você a adiciona ao tipo e revisa os lugares que tomam decisão.

Any desliga a conferência; unknown pede uma prova

any é uma saída de emergência: qualquer valor entra e qualquer operação passa pela checagem. O problema só volta na execução:

ts
const resposta: any = { total: 300 };

console.log(resposta.tota.toFixed(2));
TypeError: Cannot read properties of undefined (reading 'toFixed')

O erro de digitação em tota atravessou o compilador porque any desativou a análise naquela cadeia. unknown também recebe qualquer valor, mas bloqueia o uso até existir uma verificação:

ts
function exibirTotal(valor: unknown): string {
  if (typeof valor === 'number') {
    return valor.toFixed(2);
  }

  return 'total inválido';
}

console.log(exibirTotal(300));
console.log(exibirTotal('300'));
300.00 total inválido

typeof estreitou unknown para number dentro do if. Isso é narrowing, assunto da lição como estreitar tipos. Para JSON, formulário e resposta de API, comece com unknown e valide a forma real. Uma anotação não examina dados externos.

Null e undefined precisam de uma decisão

undefined costuma representar algo que ainda não recebeu valor ou uma propriedade ausente. null costuma ser uma ausência colocada de propósito. Com strictNullChecks, nenhum dos dois é aceito automaticamente onde se exige string.

ts
function saudacao(nome: string | null): string {
  return nome === null ? 'Olá, visitante' : `Olá, ${nome}`;
}

console.log(saudacao(null));
console.log(saudacao('Ana'));
Olá, visitante Olá, Ana

A checagem nome === null não serve apenas à execução; ela informa ao TypeScript que o segundo ramo tem uma string. Evite o operador ! para fingir que um valor existe sem prova. Ele é outra afirmação apagada na compilação e pode apenas mover o erro para produção.

Missão: descreva um produto sem usar any

Crie um tipo Produto com nome: string, preco: number, ativo: boolean, tags: string[] e status: 'rascunho' | 'publicado'. Acrescente descricao? e uma função resumo(produto: Produto): string que devolva nome, preço e status.

ts
type Produto = {
  nome: string;
  preco: number;
  ativo: boolean;
  tags: string[];
  status: 'rascunho' | 'publicado';
  descricao?: string;
};

Seu critério de sucesso é observável: um produto válido compila e gera um resumo; preço textual, status 'pronto' e tag numérica produzem três diagnósticos. Depois faça uma função receber unknown e devolver o texto somente quando typeof valor === 'string'.

Não avance só porque leu os nomes. Provoque cada erro, localize encontrado e esperado na mensagem e corrija a origem. Na próxima etapa, interface vs type em TypeScript, a gente decide como dar nomes melhores a essas formas sem transformar preferência em regra absoluta.

  • typescript
  • tipos basicos
  • string
  • number
  • union types
  • unknown

Perguntas frequentes

TypeScript tem um tipo inteiro diferente de decimal?
Não para o number comum. Inteiros e decimais usam number, como em JavaScript. bigint é outro tipo e serve para inteiros além da faixa segura de number, sem se misturar diretamente com ele nas contas.
Qual a diferença entre any e unknown?
Os dois aceitam qualquer valor, mas any permite qualquer operação sem checagem. Unknown exige verificar o tipo antes de usar, por isso é a opção mais segura para dados ainda não validados.
Quando devo anotar o tipo de uma variável?
Anote quando o valor inicial não conta toda a história ou quando existe uma fronteira importante. Para constantes locais óbvias, a inferência do compilador costuma ser mais clara.
O que significa o ponto de interrogação numa propriedade?
Ele marca a propriedade como opcional. Ao ler essa propriedade, o tipo inclui undefined, então o código precisa tratar a ausência antes de usar operações que exigem um valor presente.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0 com TypeScript 7.0.2, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. TypeScript Handbook — Everyday Types — typescriptlang.org
  2. TypeScript Handbook — More on Functions — typescriptlang.org
  3. TypeScript Handbook — Narrowing — typescriptlang.org

Continue por aqui