//
Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Restrinja tipos TypeScript em tempo de execução usando type guards, funções de asserção, o operador in e a palavra-chave satisfies. Escreva código que forneça ao TypeScript informações suficientes para inferir tipos precisos em cada branch.
// typeof narrowing
function formatValue(value: string | number | boolean) {
if (typeof value === "string") {
return value.toUpperCase(); // TypeScript sabe: string
}
if (typeof value === "number") {
return value.toFixed(2); // TypeScript sabe: number
}
return value ? "Yes" : "No"; // TypeScript sabe: boolean
}
// Custom type guard com predicado "is"
type User = { kind: "user"; name: string; email: string };
type Admin = { kind: "admin"; name: string; permissions: string[] };
type Account = User | Admin;
function isAdmin(account: Account): account is Admin {
return account.kind === "admin";
}
function AccountBadge({ account }: { account: Account }) {
if (isAdmin(account)) {
return <span>Admin: {account.permissions.length} permissões</span>;
}
return <span>Usuário: {account.email}</span>;
}// "in" operator narrowing
function renderAccount(account: Account) {
if ("permissions" in account) {
// TypeScript estreita para Admin
return <div>{account.permissions.join(", ")}</div>;
}
// TypeScript estreita para User
return <div>{account.email}</div>;
}// palavra-chave "satisfies" - valida sem alargar
const ROUTES = {
home: "/",
about: "/about",
contact: "/contact",
} satisfies Record<string, string>;
// O tipo é preservado como { home: "/"; about: "/about"; contact: "/contact" }
// Não alargado para Record<string, string>
type RouteKey = keyof typeof ROUTES; // "home" | "about" | "contact"string, number, boolean, symbol, bigint, undefined, function e object.param is Type. Quando a função retorna true, o TypeScript restringe o parâmetro para Type no escopo de chamada.in restringe com base na existência da propriedade. "email" in account restringe para os membros da união que possuem uma propriedade email.instanceof restringe instâncias de classe: if (error instanceof TypeError) restringe para TypeError.satisfies valida que uma expressão está em conformidade com um tipo sem alterar seu tipo inferido. Isso preserva tipos literais e formas específicas, garantindo a correção.asserts param is Type. Elas lançam um erro se a condição for falsa e restringem o tipo para todo o código subsequente (não apenas para o bloco if).Função de asserção:
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error(`Esperado string, obtido ${typeof value}`);
}
}
function processInput(input: unknown) {
assertIsString(input);
// TypeScript sabe que input é string a partir daqui
console.log(input.toUpperCase());
}Narrowing com Array.isArray:
function renderItems(data: string | string[]) {
if (Array.isArray(data)) {
return <ul>{data.map((item) => <li key={item}>{item}</li>)}</ul>;
}
return <p>{data}</p>;
}Narrowing de união discriminada (switch):
type AsyncState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: Error };
function renderState<T>(state: AsyncState<T>, renderData: (data: T) => React.ReactNode) {
switch (state.status) {
case "idle":
return null;
case "loading":
return <Spinner />;
case "success":
return renderData(state.data); // Estreitado: data existe
case "error":
return <ErrorMessage error={state.error} />; // Estreitado: error existe
}
}satisfies com objetos de configuração:
type ColorConfig = Record<string, { bg: string; text: string }>;
const THEME = {
primary: { bg: "#3b82f6", text: "#ffffff" },
danger: { bg: "#ef4444", text: "#ffffff" },
success: { bg: "#22c55e", text: "#ffffff" },
} satisfies ColorConfig;
// THEME.primary é totalmente tipado com valores literais
// THEME.nonExistent geraria um erroif e else. No else de isAdmin(account), o TypeScript sabe que account é User.satisfies foi adicionado no TypeScript 4.9. É especialmente valioso para objetos de configuração, mapas de rotas e definições de constantes.if. Isso as torna poderosas para validação antecipada no topo de uma função.if (x), if (x != null)) excluem null e undefined, mas também excluem valores falsy como 0 e "". Use != null para restrição precisa de null/undefined.is. Se você escrever um guard com defeito, o TypeScript estará errado sobre o tipo restringido.typeof null === "object" é uma peculiaridade do JavaScript. Use value !== null && typeof value === "object" para verificações de objeto.const { status } = state; if (status === "success") { state.data } não restringe state à variante de sucesso. Use state.status diretamente.| Abordagem | Prós | Contras |
|---|---|---|
Type guard personalizado (is) | Reutilizável, legível, explícito | A correção do guard é sua responsabilidade |
Operador in | Nenhuma função auxiliar necessária | Verifica apenas a existência da propriedade, não o tipo do valor |
instanceof | Embutido no JavaScript | Funciona apenas com classes, não com interfaces |
satisfies | Valida sem alargar | Não cria um tipo reutilizável |
Função de asserção (asserts) | Restringe todo o código subsequente | Deve lançar um erro, não pode retornar false |
Zod .parse() | Segurança em tempo de execução + tempo de compilação | Dependência externa |
if, switch, typeof, in, etc.).typeof restringe para: string, number, boolean, symbol, bigint, undefined, function e object.if (typeof value === "string"), o TypeScript sabe que value é string.function isAdmin(account: Account): account is Admin {
return account.kind === "admin";
}param is Type.true, o TypeScript restringe o parâmetro para o tipo especificado.if onde é verificado.if).false.satisfies valida que uma expressão está em conformidade com um tipo sem alterar seu tipo inferido.const x: T = ...) alarga o tipo para T.satisfies preserva tipos literais e formas específicas enquanto garante a correção.typeof value === "object" sozinho não exclui null.value !== null && typeof value === "object" para verificações seguras de objeto.if ("permissions" in account) {
// TypeScript restringe para o membro da união que tem "permissions"
account.permissions; // OK
}const { status } = state; if (status === "success") { state.data } falha porque o TypeScript perde a conexão entre status e state.state.status diretamente na verificação para manter o narrowing.// Com satisfies: preserva tipos literais
const ROUTES = {
home: "/",
about: "/about",
} satisfies Record<string, string>;
// Tipo: { home: "/"; about: "/about" }
// Com anotação: alarga para Record<string, string>
const ROUTES2: Record<string, string> = { home: "/", about: "/about" };satisfies quando quiser validação E tipos literais preservados.else de if (isAdmin(account)), o TypeScript sabe que account é User (o outro membro da união).typeof, in, instanceof e guards personalizados.function renderItems(data: string | string[]) {
if (Array.isArray(data)) {
return data.map((item) => item); // data é string[]
}
return data; // data é string
}Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥