TypeScript: Asserções de tipo no TypeScript
Última atualização: 2026-08-26
Uma asserção de tipo diz ao compilador: “Eu conheço o tipo desse valor melhor do que você” — ela não altera o tipo em tempo de execução, mas afeta apenas a verificação de tipos em tempo de compilação.
1. Noções básicas sobre asserções de tipo
(1) Duas sintaxes
// as Grammar(Recommendations,JSX "Must" must be used in)
let value: any = "hello";
let length1: number = (value as string).length;
// Angle Bracket Syntax(Cannot be in JSX Used in)
let length2: number = (<string>value).length;
as de forma consistente. A sintaxe com colchetes entra em conflito com as tags de componentes em JSX/TSX; portanto, as é uma opção mais universal.
(2) O objetivo das afirmações
Afirmações de “restrição” ou “ampliação” de tipos — instrua o TypeScript a tratar um valor como outro tipo compatível:
// Narrow:From broad types to narrow types(Common)
let value: string | number = "hello";
let str = value as string; // Tell the compiler"I'm sure this is string"
console.log(str.toUpperCase()); // ✅
// Broadening:From Narrow Types to Wide Types(Less commonly used)
let name = "Charlie" as string; // "Charlie" Type from literal "Charlie" Generalize to string
(3) As asserções não alteram os tipos em tempo de execução
let value: any = 42;
let str = value as string; // The compile-time type is string
console.log(typeof str); // "number" —— At runtime, it is still number!
// console.log(str.toUpperCase()); // Runtime Crash!number None toUpperCase
2. Cenários comuns de verificação
(1) Tipos de elementos DOM
// getElementById Back HTMLElement | null
let input = document.getElementById("myInput") as HTMLInputElement;
// After the assertion, you can use it directly. HTMLInputElement Properties of
console.log(input.value); // ✅
console.log(input.placeholder); // ✅
// A Safer Way to Write It——Check first null
let inputEl = document.getElementById("myInput");
if (inputEl instanceof HTMLInputElement) {
console.log(inputEl.value); // ✅ instanceof narrow,No assertion required
}
(2) Tipos de resposta da API
interface User {
id: number;
name: string;
email: string;
}
// JSON.parse Back any——Specify the type using an assertion
let response = JSON.parse('{"id":1,"name":"Charlie","email":"xiao@example.com"}') as User;
console.log(response.name); // ✅ Type: string
// A Safer Way to Write It——Runtime Validation (See Lesson 26)
function isUser(obj: any): obj is User {
return typeof obj.id === "number"
&& typeof obj.name === "string"
&& typeof obj.email === "string";
}
let data = JSON.parse('...');
if (isUser(data)) {
console.log(data.name); // ✅ Type Guard Narrowing,Safer than assertions
}
(3) Ignorando verificações desnecessárias de atributos
interface Config {
host: string;
port: number;
}
// Direct Assignment——Check for Unnecessary Attributes
// let cfg: Config = { host: "localhost", port: 3000, debug: true }; // ❌
// Method 1:Type Assertion Bypass
let cfg = { host: "localhost", port: 3000, debug: true } as Config; // ✅
// Method 2:Assign a value to the variable first, then pass it(Using Structured Type Compatibility)
let options = { host: "localhost", port: 3000, debug: true };
let cfg2: Config = options; // ✅ Variable assignments do not perform unnecessary property checks
▶ Exemplo: Tratamento de asserções para tipos compostos
type SuccessResponse = {
status: "success";
data: { id: number; name: string };
};
type ErrorResponse = {
status: "error";
error: { code: number; message: string };
};
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if (response.status === "success") {
// Type Narrowing(Recommendations)
console.log(response.data.name);
} else {
// Type Narrowing(Recommendations)
console.log(response.error.message);
}
// Not recommended——Replace Narrowing with Assertions
// let data = (response as SuccessResponse).data; // Danger!
}
Saída:
// Executed successfully
3. As asserções const
as const Fazer com que o TypeScript deduza o tipo literal mais preciso para um valor + readonly:
(1) Uso básico
// None as const——widening Inference
let obj = { host: "localhost", port: 3000 };
// Type:{ host: string; port: number }
obj.host = "other"; // ✅ Can be modified
// With as const — exact literals + readonly
let config = { host: "localhost", port: 3000 } as const;
// Type:{ readonly host: "localhost"; readonly port: 3000 }
// config.host = "other"; // ❌ readonly
// config.port = 8080; // ❌ readonly
(2) as const para matrizes
// Regular Arrays
let arr = [1, 2, 3];
// Type:number[]
// as const Array——become readonly Tuple
let tuple = [1, 2, 3] as const;
// Type:readonly [1, 2, 3]
// tuple[0] = 10; // ❌ readonly
// tuple.push(4); // ❌ readonly
(3) Aplicações práticas do as const — Definição de constantes e tipos de ação
// Redux Stylistic action Type Definitions
const INCREMENT = "INCREMENT" as const;
const DECREMENT = "DECREMENT" as const;
// None as const → INCREMENT The type is string(Too wide)
// With as const → INCREMENT typee is "INCREMENT"(Exact Literals)
type Action = {
type: typeof INCREMENT;
payload: number;
} | {
type: typeof DECREMENT;
payload: number;
};
function reducer(state: number, action: Action): number {
switch (action.type) {
case "INCREMENT": return state + action.payload;
case "DECREMENT": return state - action.payload;
}
}
4. Asserção de não-vazio !
Uma asserção de não-nulo indica ao TypeScript: “Tenho certeza de que este valor não é nulo nem indefinido”:
(1) Uso básico
let value: string | null = "hello";
// Non-empty assertion——Tell the compiler"The value is not null"
console.log(value!.toUpperCase()); // ✅ Compilation successful
// Equivalent to asserting that
console.log((value as string).toUpperCase());
(2) Cenários comuns
// DOM Element
let el = document.getElementById("app");
el!.innerHTML = "Hello"; // Use ! to assert non-null
// Assignment After the Optional Chain
let user: { name?: string } = { name: "Charlie" };
let nameLength = user.name!.length; // Assertion name No undefined
// Function Arguments
function process(value: string | undefined) {
// We"Know"When called value It can't be... undefined
console.log(value!.toUpperCase());
}
(3) Riscos associados a asserções não vazias
let value: string | null = null;
// Compilation successful!But it crashes during runtime——value Actually, it is null
// console.log(value!.toUpperCase()); // Runtime Error:Cannot read property of null
// ✅ A Safer Way to Write It——Check first
if (value !== null) {
console.log(value.toUpperCase()); // Type Narrowing,Compilation+All operations are safe
}
if para verificações ou ?. para encadeamento opcional — essas são alternativas mais seguras. Use ! apenas quando tiver 100% de certeza de que o valor não é nulo, mas o compilador não puder inferir isso.
5. Asserções duplas e restrições de asserção
(1) Limitações das afirmações
O TypeScript não permite asserções de tipo completamente desconexas:
let value: string = "hello";
// ✅ string → string | number(From subtype to supertype,Compatibility)
let wide = value as string | number;
// ✅ string | number → string(From Parent Type to Child Type,May not be safe, but allowed)
let narrow = wide as string;
// ❌ string → number(Completely unrelated,Not allowed)
// let num = value as number;
(2) Afirmação dupla (contorna as restrições; altamente desaconselhada)
let value: string = "hello";
// Through any Transit——Double Assertion
let num = value as unknown as number; // Compilation successful!
// But at runtime value It's still string
console.log(typeof num); // "string"
// num.toFixed(2); // Runtime Crash!
as unknown as T) ignoram completamente as verificações de segurança de tipos. É o mesmo que dizer ao compilador: “Deixa pra lá, eu assumo toda a responsabilidade” — o que é incorreto em 99% dos casos. Se você perceber que precisa usar asserções duplas, é altamente provável que haja um problema no projeto do seu código, e você deve repensar sua estrutura de tipos.**
6. Melhores práticas para asserções
(1) Ordenação por prioridade
Type Narrowing(if/typeof/instanceof/in) → Safest,Use as a priority
Type Guard(Custom is Function) → Safety,Collapse Complex Types
Non-empty assertion ! → Use with caution,When it is determined that the value is not empty
as Assertion → Use less,When there is a clear reason
as const → Recommended for constant definitions
Double Assertion as unknown as T → Highly not recommended,99%This is incorrect usage.
(2) Lista de verificação de segurança de asserções
Antes de escrever uma asserção as, faça a si mesmo três perguntas:
- Posso usar o estreitamento de tipos em vez disso? (if/typeof/instanceof)
- Posso mudar para o encadeamento opcional? (
?.) - Se uma asserção falhar, o programa irá travar durante a execução?
Se a sua resposta à Pergunta 3 for “Sim”, considere um método mais seguro.
▶ Exemplo: Comparação entre asserções seguras e inseguras
interface User {
id: number;
name: string;
email: string;
}
// ❌ Unsafe——Blind assertions API Response
function fetchUser1(id: number): User {
let data = JSON.parse(localStorage.getItem(`user:${id}`) ?? "{}") as User;
return data; // data May not match User Structure
}
// ✅ Safety——Runtime Validation + Type Guard
function isUser(obj: any): obj is User {
return obj
&& typeof obj.id === "number"
&& typeof obj.name === "string"
&& typeof obj.email === "string";
}
function fetchUser2(id: number): User | null {
let raw = localStorage.getItem(`user:${id}`);
if (!raw) return null;
let data = JSON.parse(raw);
if (isUser(data)) {
return data; // ✅ Type Guard: Return safely after confirmation
}
return null;
}
Saída:
// Executed successfully
▶ Exemplo: Sintaxe as vs sintaxe de colchetes angulares
Saída:
19
19
let value: unknown = "Hello, TypeScript!";
// as syntax (recommended — works in JSX/TSX)
let len1: number = (value as string).length;
// Angle-bracket syntax (cannot be used in JSX)
let len2: number = (<string>value).length;
console.log(len1); // 19
console.log(len2); // 19
// Both produce identical runtime code —
// the choice is purely about JSX compatibility
Saída:
19
19
❓ Perguntas Frequentes
P: Qual é a diferença entre uma asserção de tipo e uma conversão de tipo? R: Uma asserção de tipo afeta apenas a verificação de tipos em tempo de compilação e não altera o valor em tempo de execução —
x as stringnão transforma x em uma string. Uma conversão de tipo altera o tipo de um valor em tempo de execução —String(42)realmente transforma 42 em “42”. Oasdo TypeScript é uma asserção, não uma conversão.
P: Qual é a diferença entre
as constereadonly? R:readonlymarca uma única propriedade como somente leitura.as consttransforma todo o objeto ou array — em todos os níveis — em um tipo literal comreadonly.const x = { a: 1 } as consté mais conciso quelet x: { readonly a: 1 }e oferece proteção profunda contra leitura.
P: Quando é apropriado usar a asserção “não vazio”!? R: O cenário mais apropriado é a manipulação do DOM — quando você tem certeza de que um determinado elemento existe no HTML, mas o TypeScript não consegue verificar isso.
document.getElementById("app")!.innerHTML = "Hi"É apropriado quando a estrutura da página é conhecida. Em outros cenários, use uma instruçãoifpara fazer a verificação.
P: Quais são alguns usos legítimos para
as unknown as T(duplas asserções)? R: Muito poucos. O único cenário razoável é quando o sistema de tipos realmente não consegue expressar o comportamento pretendido (como em certas operações genéricas complexas ou quando as definições de tipos de bibliotecas de terceiros contêm erros). No entanto, 99% das duplas asserções podem ser evitadas redesenhando-se a estrutura de tipos.
📖 Resumo
- Uma asserção de tipo
as Tinstrui o compilador a “tratar o valor como sendo do tipo T” — ela entra em vigor na fase de compilação e não tem impacto na fase de execução. - Cenários comuns: tipos de elementos DOM, tipos de resposta da API, como evitar verificações desnecessárias de atributos
as constInferência de valores como literais exatos + somente leitura — recomendado para definições de constantes- Asserção de valor não nulo
!: O valor da asserção não é nulo nem indefinido — use com cautela; priorize se houver verificações - Asserção dupla
as unknown as TIgnora completamente a segurança de tipos — altamente desaconselhada - Use restrição de tipo > verificações de tipo > asserções de não-nulo > asserções
asnessa ordem
📝 Exercícios
- Problema básico (Dificuldade ⭐): Use
as constpara definir uma constante de direçãoDIRECTIONS = ["north", "south", "east", "west"] as conste, em seguida, escreva uma função que aceite um parâmetro do tipotypeof DIRECTIONS[number]para verificar se apenas quatro valores de direção são válidos. - Problema avançado (Dificuldade ⭐⭐): Escreva uma função
querySelector<T extends HTMLElement>(selector: string): T | nullque utilizedocument.querySelector(selector) as T | nullinternamente. Em seguida, crie uma chamada que localize o elementoinpute acesse a propriedadevalueusando uma asserção de não-nulo. Escreva uma versão mais segura que utilize uma instruçãoifem vez da asserção de não-nulo. - Desafio (Dificuldade: ⭐⭐⭐): Implemente uma função de verificação de tipo em tempo de execução
validate<T>(schema: Schema, value: unknown): value is Tque utilize objetos de esquema simples para descrever regras de verificação (como{ name: "string", age: "number" }) e verifique em tempo de execução se um valorunknowncorresponde; caso corresponda, a restrição de tipo é reduzida paraT. Compare isso comas Te explique em que consiste a segurança.