TypeScript: Variáveis e inferência de tipos no TypeScript
Última atualização: 2026-08-26
Um dos recursos mais poderosos do TypeScript é a “inferência de tipos” — você não precisa escrever anotações de tipo em todos os lugares; o compilador as infere automaticamente para você. No entanto, é preciso compreender as regras de inferência para escrever código que o compilador possa interpretar corretamente.
1. Declaração de variáveis: let, const e var
O TypeScript oferece suporte total às três formas de declarar variáveis no JavaScript, mas recomenda-se usar let e const:
(1) let — uma variável que pode ser reatribuída
let count = 0;
count = 1; // ✅ let Variables can be reassigned
(2) const — uma constante que não pode ser reatribuída
const MAX_SIZE = 100;
MAX_SIZE = 200; // ❌ Error:Cannot be assigned to a constant
(3) var — Âmbito da função (não recomendado)
var x = 1; // ⚠️ Available but not recommended——var There are issues with variable hoisting and scope leakage.
let e const; não use var. Se for possível usar const, use const em vez disso (quando o valor permanecer inalterado); use let somente quando for necessário reatribuir o valor. Isso está totalmente de acordo com as melhores práticas do JavaScript.
(4) Anotações de tipo versus inferência de tipo
// Type Annotations——Tell me TypeScript What is the type of the variable?
let age: number = 25;
// Type Inference——TypeScript Automatically determine the type based on the initial value
let name = "Charlie"; // TypeScript Inferred as string
let active = true; // TypeScript Inferred as boolean
Ambas as abordagens produzem o mesmo resultado, mas, quando um valor inicial é fornecido, recomenda-se omitir a anotação para que a inferência de tipos possa ocorrer.
2. Regras completas para inferência de tipos
A inferência de tipos não é “adivinhação” — ela segue regras claras. Somente ao compreender essas regras é que você poderá prever o comportamento do compilador.
(1) Regra 1: Inferência dos valores iniciais
Quando uma variável possui um valor inicial, o TypeScript infere seu tipo com base nesse valor inicial:
let message = "hello"; // Inferred as string
let count = 42; // Inferred as number
let flag = true; // Inferred as boolean
let items = [1, 2, 3]; // Inferred as number[]
(2) Regra 2: Inferência de tipo para literais const
Esse é um dos detalhes mais sutis da inferência de tipos do TypeScript — os resultados da inferência para let e const são diferentes:
// let Inferred as a wide type(widening)
let x = "hello"; // Inferred as string
let n = 42; // Inferred as number
let b = true; // Inferred as boolean
// const Inferred as an exact literal type(no widening)
const x2 = "hello"; // Inferred as "hello"(Literal types,No string)
const n2 = 42; // Inferred as 42(Literal types,No number)
const b2 = true; // Inferred as true(Literal types,No boolean)
let A variável pode ser reatribuída, por isso infere-se que ela tenha um tipo mais amplo (um string pode conter qualquer string); const A variável permanece inalterada, por isso infere-se que ela tenha exatamente o tipo literal. Esse comportamento é chamado de ampliação.
(3) Regra 3: Se nenhum valor inicial for especificado, ele será inferido como any
Se uma variável for declarada sem um valor inicial ou uma anotação de tipo, o TypeScript a infere como any:
let something; // Inferred as any(Danger!)
something = 42; // any,Do not check
something = "hello"; // any,Do not check——Completely bypassed the type system
any desativa efetivamente a verificação de tipos, o que torna essa abordagem idêntica à programação em JavaScript. Quando o modo strict está ativado, variáveis sem valores iniciais geram um erro (é necessário especificar explicitamente o tipo ou fornecer um valor inicial).
(4) Regra 4: Melhor inferência de tipos pública
Ao inferir tipos a partir de várias fontes, o TypeScript procura o “melhor tipo comum” entre elas:
let arr = [1, "hello", true];
// Inferred as (number | string | boolean)[] —— Union Type Arrays
let arr2 = [1, 2, 3];
// Inferred as number[] —— All elements are of the same type,Inferred as an array of element types
▶ Exemplo: Experimento de inferência de tipos
// Experiment1:let vs const Differences in Inference
let dynamicText = "hello";
const fixedText = "hello";
dynamicText = "world"; // ✅ string Can accept another string
// fixedText = "world"; // ❌ const Cannot be reassigned
// Experiment2:Inference of Object Properties
let user = {
name: "Charlie",
age: 20
};
// Inferred as { name: string; age: number }
user.name = "Diana"; // ✅ string Properties can be assigned new values
user.age = 21; // ✅ number Properties can be assigned new values
// Experiment3:const Object——The property can still be modified!
const config = {
host: "localhost",
port: 3000
};
config.host = "127.0.0.1"; // ✅ const Only reassigning the object itself is prohibited.,Non-freezing property
// config = { host: "x", port: 1 }; // ❌ You cannot reassign the entire object
Saída:
// Executed successfully
3. Noções básicas sobre compatibilidade de tipos
A compatibilidade de tipos do TypeScript utiliza o “subtipagem estrutural” — os tipos são compatíveis desde que suas estruturas coincidam, sem que seja necessário que os nomes dos tipos sejam os mesmos.
(1) Compatibilidade de subtipos
let num: number = 42;
let big: bigint = 100n;
// num = big; // ❌ bigint No number subtypes of
// big = num; // ❌ number No bigint subtypes of
(2) Os tipos literais são subtipos dos tipos largos
let text: string = "hello"; // string Type
const literal: "hello" = "hello"; // Literal types "hello"
text = literal; // ✅ "hello" is a string subtype of,Can be assigned a value
// literal = text; // ❌ string No "hello" subtypes of
(3) “qualquer” refere-se à “cápsula de fuga”
let a: any = "hello";
a = 42; // ✅ any Can accept any type
a = true; // ✅ any No tests will be performed
let b: string = a; // ✅ any It can also be assigned to any type.(Danger!)
any viola a segurança de tipos e só deve ser usado nas seguintes situações: (1) prototipagem rápida, (2) migração de código JavaScript legado ou (3) como uma solução alternativa temporária quando uma biblioteca de terceiros não possui definições de tipos. any deve ser evitado no desenvolvimento normal.
4. Combinando asserções de tipo e inferência de tipo
Se o resultado da inferência não for o desejado, você pode substituí-lo por meio de uma asserção de tipo:
// Scene:DOM Type Inference for Elements
let input = document.getElementById("myInput");
// Inferred as HTMLElement | null——I don't know exactly what element it is.
let inputEl = document.getElementById("myInput") as HTMLInputElement;
// Assert that HTMLInputElement——Tell the compiler"I'm sure this is input Element"
5. Estratégias de inferência no desenvolvimento prático
(1) Estratégia 1: Se você puder deduzir, não anote
// ❌ Redundancy
let name: string = "Charlie";
const MAX: number = 100;
function add(a: number, b: number): number { return a + b; }
// ✅ Concise
let name = "Charlie";
const MAX = 100;
function add(a: number, b: number) { return a + b; } // The return type is inferred as number
(2) Estratégia 2: As interfaces e os aliases de tipo devem ser especificados
interface User {
name: string;
age: number;
}
// When an object literal is assigned to a typed variable,Inference+Type checking takes effect simultaneously
let user: User = { name: "Charlie", age: 20 }; // ✅ Structural Matching
let bad: User = { name: "Charlie" }; // ❌ Missing age Properties
(3) Estratégia 3: Identificar explicitamente expressões complexas
// Return Values of Complex Functions——It is recommended to explicitly label them.,Avoiding Fallacies in Reasoning
function getUserInfo(id: number): { name: string; age: number } | null {
if (id <= 0) return null;
return { name: "User" + id, age: 20 };
}
▶ Exemplo: Inferência na prática — Objetos de configuração
// Use as const assertion to make object properties read-only literal types
const THEME = {
primary: "#4A90D9",
secondary: "#7B51D9",
fontSize: 14
} as const;
// Inference Results:
// { readonly primary: "#4A90D9"; readonly secondary: "#7B51D9"; readonly fontSize: 14 }
// Each property is of an exact literal type + readonly
// THEME.primary = "#000"; // ❌ readonly Properties cannot be modified
// THEME.fontSize = 16; // ❌ readonly Properties cannot be modified
console.log(THEME.primary); // "#4A90D9"
console.log(THEME.fontSize); // 14
Saída:
#4A90D9
14
as const: Ele instrui o TypeScript a inferir o tipo literal mais preciso para o valor (sem ampliação) e a aplicar o modificador readonly. É comumente usado em cenários como a definição de configurações constantes e tipos de ação.
▶ Exemplo: Inferência de tipos com arrays e objetos
// Array inference — element type is inferred automatically
let scores = [90, 85, 92]; // number[]
let names = ["Alice", "Bob"]; // string[]
let mixed = [1, "two", true]; // (number | string | boolean)[]
// Object inference — each property gets its own type
let point = { x: 10, y: 20 }; // { x: number; y: number }
let user = { name: "Eve", active: true }; // { name: string; active: boolean }
// Nested inference
let config = {
server: { host: "localhost", port: 3000 },
debug: true
};
// { server: { host: string; port: number }; debug: boolean }
console.log(config.server.host); // "localhost"
console.log(typeof mixed[0]); // "number"
Saída:
localhost
number
❓ Perguntas Frequentes
P: Quando é necessário especificar manualmente as anotações de tipo? R: Em três situações: (1) Parâmetros de função — quando não há valor inicial para a inferência de tipo; (2) Declarações de variáveis sem valores iniciais — caso contrário, o tipo é inferido como
any; (3) Tipos de retorno que não correspondem às expectativas — quando o tipo inferido é muito amplo ou muito restrito, ele deve ser substituído.
P: Quais são as implicações práticas da diferença na inferência de tipos entre
leteconst? R:leté inferido como um tipo amplo (comostringounumber), enquantoconsté inferido como um tipo literal (como “hello” ou 42). Essa diferença afeta principalmente a correspondência entre tipos de união e tipos literais. Por exemplo, ao definir uma constante de string comconst, o tipo é inferido como um literal exato, que pode ser usado como um discriminador para tipos de união.
P: Qual é a relação entre
anye o TypeScript? É uma boa ideia usarany? R:anyé a “saída de emergência de tipos” do TypeScript — ela desativa a verificação de tipos, revertendo efetivamente para o modo JavaScript. Você não deve usaranya menos que esteja migrando código legado ou contornando temporariamente um problema de tipo. Se não tiver certeza sobre um tipo, usarunknown(explicado em detalhes na Lição 5) é mais seguro do que usarany.
P: O que é
as const? Em que difere doconstcomum? R: Oconstcomum apenas impede que uma variável seja reatribuída; a inferência de tipo ainda permite o alargamento (por exemplo,const x = "hi"é inferido como"hi", mas as propriedades do objeto permanecem do tipo mais amplo).as consté uma asserção de tipo que faz com que todos os níveis sejam inferidos como literais maisreadonly. Somente usandoas constcom objetos ou matrizes é possível obter um comportamento verdadeiramente “somente leitura” profundo.
📖 Resumo
- Use
letpara declarar variáveis mutáveis,constpara declarar constantes e não usevar - Regras de inferência de tipo: Se for fornecido um valor inicial, o tipo é inferido por valor;
consté inferido como um tipo literal (sem ampliação);leté inferido como um tipo ampliado (ampliação); se nenhum valor inicial for fornecido, o tipo é inferido comoany. anyDesativar a verificação de tipos; isso deve ser evitado sempre que possível;as constTornar a inferência um literal exato + somente leitura- Estratégia de desenvolvimento efetiva: omitir se for possível inferir; os parâmetros das funções devem ser documentados; recomenda-se documentar valores de retorno complexos
- A compatibilidade de tipos segue o subtipagem estruturada: os tipos literais são compatíveis com tipos mais amplos, mas não o contrário.
📝 Exercícios
- Exercício básico (Dificuldade ⭐): Declare uma variável de string usando
lete outra usandoconst, e imprima seus valores. Em seguida, tente reatribuir valores a elas e observe como o TypeScript lida com o erro. - Problema avançado (Dificuldade ⭐⭐): Defina um objeto de configuração
as constchamadoCOLORSque contenha três valores hexadecimais de cor: vermelho, verde e azul. Em seguida, tente modificar uma das cores e observe a mensagem de erro gerada pela restriçãoreadonly. - Desafio (Dificuldade: ⭐⭐⭐): Escreva uma função
createUser(name: string, age: number)sem especificar um tipo de retorno, permitindo que o TypeScript infira o tipo de retorno. Em seguida, use uma variável tipada fora da função para receber o valor de retorno e verifique se a inferência está correta.