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

TYPESCRIPT
// 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;
📌 Recomendação: Use a sintaxe 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:

TYPESCRIPT
// 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

TYPESCRIPT
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
🔥 Princípio fundamental: as asserções de tipo não realizam nenhuma conversão em tempo de execução. Elas são meramente anotações de tipo em tempo de compilação. Se uma asserção falhar, ainda assim ocorrerá um erro em tempo de execução.



2. Cenários comuns de verificação

(1) Tipos de elementos DOM

TYPESCRIPT
// 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

TYPESCRIPT
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

TYPESCRIPT
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

TYPESCRIPT
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!
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
// 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

TYPESCRIPT
// 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

TYPESCRIPT
// 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

TYPESCRIPT
// 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

TYPESCRIPT
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

TYPESCRIPT
// 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

TYPESCRIPT
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
}
💡 Recomendação: As asserções de valor não nulo devem ser um último recurso. Sempre que possível, use 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:

TYPESCRIPT
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)

TYPESCRIPT
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!
⚠️ Aviso: As asserções duplas (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

TEXT 📖 Somente leitura
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:

  1. Posso usar o estreitamento de tipos em vez disso? (if/typeof/instanceof)
  2. Posso mudar para o encadeamento opcional? (?.)
  3. 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

TYPESCRIPT
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;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
// Executed successfully


▶ Exemplo: Sintaxe as vs sintaxe de colchetes angulares

Saída:

TEXT 📖 Somente leitura
19
19
TYPESCRIPT
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:

TEXT 📖 Somente leitura
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 string nã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”. O as do TypeScript é uma asserção, não uma conversão.

P: Qual é a diferença entre as const e readonly? R: readonly marca uma única propriedade como somente leitura. as const transforma todo o objeto ou array — em todos os níveis — em um tipo literal com readonly. const x = { a: 1 } as const é mais conciso que let 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ção if para 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

📝 Exercícios

  1. Problema básico (Dificuldade ⭐): Use as const para definir uma constante de direção DIRECTIONS = ["north", "south", "east", "west"] as const e, em seguida, escreva uma função que aceite um parâmetro do tipo typeof DIRECTIONS[number] para verificar se apenas quatro valores de direção são válidos.
  2. Problema avançado (Dificuldade ⭐⭐): Escreva uma função querySelector<T extends HTMLElement>(selector: string): T | null que utilize document.querySelector(selector) as T | null internamente. Em seguida, crie uma chamada que localize o elemento input e acesse a propriedade value usando uma asserção de não-nulo. Escreva uma versão mais segura que utilize uma instrução if em vez da asserção de não-nulo.
  3. Desafio (Dificuldade: ⭐⭐⭐): Implemente uma função de verificação de tipo em tempo de execução validate<T>(schema: Schema, value: unknown): value is T que 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 valor unknown corresponde; caso corresponda, a restrição de tipo é reduzida para T. Compare isso com as T e explique em que consiste a segurança.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%