TypeScript: Guards de tipo e restrição de tipo no TypeScript

Última atualização: 2026-08-26

O estreitamento de tipos é um dos recursos mais práticos do TypeScript — ele restringe tipos amplos a um escopo mais preciso, permitindo que você acesse com segurança propriedades e métodos de tipos específicos.

1. Visão geral do estreitamento de tipos

Variáveis de um tipo de união só podem acessar propriedades compartilhadas por todos os membros. O estreitamento de tipo nos permite “estreitar” o tipo em um ramo específico do código para acessar membros exclusivos desse ramo:

TYPESCRIPT
function process(value: string | number) {
  // Before narrowing——value Only shared methods can be used
  console.log(value.toString());  // ✅ string and number All of them

  // After narrowing——value You can use a specific method
  if (typeof value === "string") {
    console.log(value.toUpperCase());  // ✅ string Unique Approach
  } else {
    console.log(value.toFixed(2));     // ✅ number Unique Approach
  }
}

O TypeScript oferece suporte aos seguintes tipos de restrição:

Método de restrição Cenários aplicáveis
typeof Verificação de tipo básica
instanceof Verificação de instância de classe
in Operador A propriedade existe?
Verificação de igualdade Comparação ===/!==
Proteções de tipos personalizadas Verificações de tipos complexos
Com opção de redução Reduzir automaticamente durante a atribuição


2. Restrição do typeof

typeof Mais comumente usado para distinguir entre tipos básicos:

(1) Uso básico

TYPESCRIPT
function padLeft(value: string, padding: string | number): string {
  if (typeof padding === "number") {
    return " ".repeat(padding) + value;    // padding narrowed to number
  }
  return padding + value;                   // padding narrowed to string
}

console.log(padLeft("hello", 4));      // "    hello"
console.log(padLeft("hello", ">>>"));  // ">>>hello"

(2) O valor de retorno de typeof

TYPESCRIPT
typeof "hello"     // "string"
typeof 42          // "number"
typeof true        // "boolean"
typeof undefined   // "undefined"
typeof Symbol()    // "symbol"
typeof 100n        // "bigint"
typeof {}          // "object"   ⚠️ Including null, Array, Date, etc.
typeof function(){} // "function"
🔥 Erro comum: typeof null === "object" é um bug histórico do JavaScript. Não é possível usar typeof para distinguir entre null e outros objetos — é preciso usar === null para verificar.

(3) typeof com switch

TYPESCRIPT
function describe(value: string | number | boolean | undefined) {
  switch (typeof value) {
    case "string":
      return `String:${value.toUpperCase()}`;
    case "number":
      return `Numbers:${value.toFixed(2)}`;
    case "boolean":
      return `Boolean:${value}`;
    case "undefined":
      return "Undefined";
  }
}


3. Restrição do instanceof

instanceof Verifica se um objeto é uma instância de uma determinada classe — adequado para restringir tipos de referência:

(1) Uso básico

TYPESCRIPT
function formatValue(value: Date | string | Error): string {
  if (value instanceof Date) {
    return value.toISOString();         // Date Methods
  } else if (value instanceof Error) {
    return value.message;               // Error Properties
  } else {
    return value.toUpperCase();         // string Methods
  }
}

console.log(formatValue(new Date()));          // "2024-..."
console.log(formatValue(new Error("Error")));   // "Error"
console.log(formatValue("hello"));             // "HELLO"

(2) Limitações do instanceof

instanceof Só pode ser usado com instâncias de classe — não com interfaces ou aliases de tipo (que não existem em tempo de execução):

TYPESCRIPT
interface Dog { bark(): void; }
interface Cat { meow(): void; }

// ❌ instanceof Cannot be used for interfaces
// if (pet instanceof Dog) { ... }

// ✅ Do you need to use a custom type guard or in Operator

(3) Classes personalizadas e instanceof

TYPESCRIPT
class NetworkError extends Error {
  constructor(public statusCode: number) {
    super(`Network Error:${statusCode}`);
  }
}

class ValidationError extends Error {
  constructor(public field: string) {
    super(`Validation Error:${field}`);
  }
}

function handleError(error: NetworkError | ValidationError): string {
  if (error instanceof NetworkError) {
    return `HTTP ${error.statusCode} Error`;
  } else {
    return `Field ${error.field} Invalid`;
  }
}


4. Restrição do operador in

in Verifica se um objeto possui uma propriedade específica — útil para distinguir entre interfaces e aliases de tipo:

(1) Uso básico

TYPESCRIPT
interface Fish {
  swim(): void;
}

interface Bird {
  fly(): void;
}

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();   // ✅ Fish Type
  } else {
    animal.fly();    // ✅ Bird Type
  }
}

(2) Atributos distinguíveis

TYPESCRIPT
interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape): number {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius ** 2;   // ✅ Circle 's radius
  } else {
    return shape.sideLength ** 2;          // ✅ Square 's sideLength
  }
}

▶ Exemplo: Tratamento de eventos com segurança de tipos

TYPESCRIPT
interface ClickEvent {
  type: "click";
  x: number;
  y: number;
}

interface KeyEvent {
  type: "keydown" | "keyup";
  key: string;
  ctrlKey: boolean;
}

interface ScrollEvent {
  type: "scroll";
  scrollTop: number;
  scrollLeft: number;
}

type UIEvent = ClickEvent | KeyEvent | ScrollEvent;

function handleEvent(event: UIEvent): string {
  switch (event.type) {
    case "click":
      return `Click here:(${event.x}, ${event.y})`;
    case "keydown":
    case "keyup":
      return `Button:${event.key},Ctrl:${event.ctrlKey}`;
    case "scroll":
      return `Scroll:top=${event.scrollTop}, left=${event.scrollLeft}`;
  }
}

console.log(handleEvent({ type: "click", x: 100, y: 200 }));
console.log(handleEvent({ type: "keydown", key: "Enter", ctrlKey: false }));
console.log(handleEvent({ type: "scroll", scrollTop: 50, scrollLeft: 0 }));
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Click here:(100, 200)
Button:Enter,Ctrl:false
Scroll:top=50, left=0


5. Guarda de tipos personalizados

Quando os métodos de restrição integrados não forem suficientes, você pode escrever funções personalizadas de verificação de tipo:

(1) Predicado de tipo

TYPESCRIPT
interface Dog {
  bark(): void;
  breed: string;
}

interface Cat {
  meow(): void;
  color: string;
}

// Type Predicates:The return value is "Parameter Name is Type"
function isDog(animal: Dog | Cat): animal is Dog {
  return "bark" in animal;
}

function interact(animal: Dog | Cat) {
  if (isDog(animal)) {
    animal.bark();    // ✅ narrowed to Dog
    console.log(animal.breed);
  } else {
    animal.meow();    // ✅ narrowed to Cat
    console.log(animal.color);
  }
}

(2) Função de afirmação

As funções de asserção lançam uma exceção quando a condição não é satisfeita — indicando ao TypeScript: “Se esta linha for executada, a condição deve ser verdadeira”:

TYPESCRIPT
function assertDefined<T>(value: T | undefined | null, message?: string): asserts value is NonNullable<T> {
  if (value == null) {
    throw new Error(message ?? "The value cannot be null or undefined");
  }
}

function processUser(user: User | undefined) {
  assertDefined(user, "User does not exist");
  // After that user The type has been narrowed down to User(Excludes undefined)
  console.log(user.name.toUpperCase());  // ✅ Safety
}

(3) Asserções versus predicados de tipo

Propriedade Predicado de tipo x is T Função de afirmação asserts x is T
Valor de retorno booleano nulo (lança uma exceção se a condição não for satisfeita)
Uso if (isType(x)) assertIsType(x)
Restrição de tipo Restrição em um ramo “if” Restrição automática após uma chamada
Cenários adequados Tratamento de ramificações pós-verificação Verificações de pré-requisitos


6. Restrição da atribuição

As operações de atribuição também realizam o estreitamento de tipos:

TYPESCRIPT
let value: string | number;

value = "hello";
console.log(value.toUpperCase());  // ✅ After assignment, it narrows to string

value = 42;
console.log(value.toFixed(2));     // ✅ After assignment, it narrows to number

(1) Análise do fluxo de controle

O TypeScript acompanha as mudanças no tipo de uma variável ao longo do fluxo de controle:

TYPESCRIPT
function example(x: string | number | boolean) {
  // x: string | number | boolean
  if (typeof x === "string") {
    // x: string
    console.log(x.toUpperCase());
  } else {
    // x: number | boolean
    if (typeof x === "number") {
      // x: number
      console.log(x.toFixed(2));
    } else {
      // x: boolean
      console.log(x);
    }
  }
}

(2) Restrição e reatribuição

TYPESCRIPT
let value: string | number;

value = "hello";
console.log(value.length);  // ✅ string

value = 42;
// console.log(value.length);  // ❌ number None length

value = true;  // ❌ boolean Not in a composite type


7. Verificação exaustiva

Certifique-se de que a instrução switch/if abranja todos os tipos possíveis — use o tipo never para garantir a exaustividade:

TYPESCRIPT
type Shape = "circle" | "square" | "triangle";

function getIcon(shape: Shape): string {
  switch (shape) {
    case "circle": return "○";
    case "square": return "□";
    case "triangle": return "△";
    default: {
      // If all case It's all taken care of.,shape Here is never
      const _exhaustive: never = shape;
      return _exhaustive;
    }
  }
}

// If in the future Shape Added "hexagon" But I didn't add it case
// default Branched _exhaustive Report Type Error
// This is a reminder to fill in any missing information. case

(1) Uma verificação exaustiva mais concisa

TYPESCRIPT
function assertNever(value: never): never {
  throw new Error(`Unprocessed values:${value}`);
}

type Action = "create" | "update" | "delete";

function handleAction(action: Action) {
  switch (action) {
    case "create": /* ... */ break;
    case "update": /* ... */ break;
    case "delete": /* ... */ break;
    default:
      assertNever(action);  // If omitted case,A type error will be reported here.
  }
}


▶ Exemplo: typeof e instanceof para estreitamento de tipos

TYPESCRIPT
function format(value: string | number | Date): string {
  if (typeof value === "string") {
    return value.trim().toUpperCase();
  } else if (typeof value === "number") {
    return value.toFixed(2);
  } else if (value instanceof Date) {
    return value.toISOString();
  }
  return String(value);
}

console.log(format("  hello  "));        // "HELLO"
console.log(format(3.14159));            // "3.14"
console.log(format(new Date("2024-01-01"))); // "2024-01-01T00:00:00.000Z"
▶ Experimente

Saída:

TEXT 📖 Somente leitura
HELLO
3.14
2024-01-01T00:00:00.000Z

▶ Exemplo: Guarda de tipo personalizado com uniões discriminadas

TYPESCRIPT
interface Circle { kind: "circle"; radius: number; }
interface Rectangle { kind: "rectangle"; width: number; height: number; }
type Shape = Circle | Rectangle;

function isCircle(shape: Shape): shape is Circle {
  return shape.kind === "circle";
}

function area(shape: Shape): number {
  if (isCircle(shape)) {
    return Math.PI * shape.radius ** 2;   // Circle
  }
  return shape.width * shape.height;       // Rectangle
}

console.log(area({ kind: "circle", radius: 5 }));       // 78.54
console.log(area({ kind: "rectangle", width: 4, height: 6 })); // 24
▶ Experimente

Saída:

TEXT 📖 Somente leitura
78.53981633974483
24

❓ Perguntas Frequentes

P: Qual é a diferença entre typeof e instanceof? R: typeof verifica o “tipo primitivo” de um valor (string/número/booleano/indefinido/objeto/função) e retorna uma string; é adequado para verificar tipos primitivos. instanceof verifica se um valor é uma instância de uma determinada classe; é adequado para verificar tipos de referência (como Date, Error e classes personalizadas). Os dois são complementares e não se excluem mutuamente.

P: Qual é o impacto no desempenho das verificações de tipo personalizadas? R: Nenhum. As verificações de tipo são usadas apenas em tempo de compilação — o JavaScript compilado consiste em instruções if comuns e verificações de propriedades. Os predicados de tipo (x is T) e as funções de asserção (asserts x is T) não existem em tempo de execução, portanto, a sobrecarga é zero.

P: Por que o operador in permite o estreitamento de tipos? R: Porque o TypeScript sabe que, se um objeto possui uma determinada propriedade, ele deve pertencer a uma interface que inclua essa propriedade. Quando "swim" in animal é verdadeiro, animal deve implementar uma interface que inclua swim. Trata-se de uma inferência lógica que não requer informações de tipo em tempo de execução.

P: Quando é necessário escrever verificadores de tipo personalizados? R: Quando os métodos integrados de restrição de tipo (typeof, instanceof, in, ===) não conseguem distinguir entre tipos. O cenário mais comum é a distinção entre interfaces — como as interfaces não existem em tempo de execução, não é possível verificá-las usando instanceof; em vez disso, é preciso usar in para verificar se há propriedades identificáveis ou escrever verificadores de tipo personalizados.

📖 Resumo

📝 Exercícios

  1. Problema básico (Dificuldade ⭐): Escreva uma função doubleOrRepeat(value: string | number) — se value for um número, multiplique-o por 2; se for uma sequência de caracteres, concatene-a consigo mesma uma vez (por exemplo, “hi” → “hihi”). Use typeof para restringir a entrada.
  2. Problema avançado (Dificuldade ⭐⭐): Defina duas interfaces, Admin (com o método hasPermission) e Guest (com o método requestAccess), e refine-as usando o atributo distinguível role. Escreva uma função que chame métodos diferentes com base na função.
  3. Desafio (Dificuldade: ⭐⭐⭐): Escreva um tipo de verificação personalizado isNonNull<T>(value: T | null | undefined): value is NonNullable<T> e, em seguida, use-o na função filterNonNull<T>(arr: (T | null | undefined)[]): T[] para filtrar valores nulos e indefinidos e retornar um array não vazio.
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%