Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tipifique suas chamadas useSWR com genéricos para obter segurança de tipo completa em data, error, chaves e funções fetcher. O suporte TypeScript do SWR permite a inferência de tipos de retorno das assinaturas do fetcher.
"use client";
import useSWR from "swr";
interface User {
id: string;
name: string;
email: string;
}
const fetcher = (url: string): Promise<User> =>
fetch(url).then((r) => r.json());
function Profile() {
const { data, error } = useSWR<User, Error>("/api/me", fetcher);
// data: User | undefined
// error: Error | undefined
if (data) {
return <div>{data.name}</div>; // data é User aqui
}
}"use client";
import useSWR, { Fetcher, SWRConfiguration, Key } from "swr";
import useSWRMutation, { SWRMutationConfiguration } from "swr/mutation";
// ---- Fábrica de fetcher type-safe ----
function createFetcher<T>(): Fetcher<T, string> {
return async (url: string) => {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json() as Promise<T>;
};
}
// ---- Tipos de domínio ----
interface Product {
id: string;
name: string;
price: number;
category: string;
}
interface CreateProductInput {
name: string;
price: number;
category: string;
}
// ---- Hooks type-safe ----
function useProduct(id: string) {
return useSWR<Product, Error>(
`/api/products/${id}`,
createFetcher<Product>()
);
}
function useProducts(category?: string) {
const key = category ? `/api/products?category=${category}` : "/api/products";
return useSWR<Product[], Error>(key, createFetcher<Product[]>());
}
// ---- Mutação type-safe ----
async function createProduct(
url: string,
{ arg }: { arg: CreateProductInput }
): Promise<Product> {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(arg),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
function useCreateProduct() {
return useSWRMutation<Product, Error, string, CreateProductInput>(
"/api/products",
createProduct
);
}
// ---- Uso ----
export default function ProductPage({ id }: { id: string }) {
const { data: product, error, isLoading } = useProduct(id);
const { trigger, isMutating } = useCreateProduct();
if (isLoading) return <div>Carregando...</div>;
if (error) return <div>Erro: {error.message}</div>;
return (
<div>
<h1>{product?.name}</h1>
<p>${product?.price}</p>
<button
onClick={() =>
trigger({ name: "Novo Item", price: 29.99, category: "widgets" })
}
disabled={isMutating}
>
Adicionar Produto
</button>
</div>
);
}useSWR<Data, Error, Key> aceita até três parâmetros genéricos: o tipo dos dados, o tipo do erro e o tipo da chave.Data do tipo de retorno do fetcher.Fetcher<Data, Key> do SWR garante que o fetcher aceite o tipo de chave e retorne Promise<Data>.useSWRMutation<Data, Error, Key, Arg> adiciona um quarto genérico para o tipo do argumento de mutação.SWRResponse, SWRConfiguration, Key e Fetcher para tipagem avançada.Tipos inferidos do fetcher:
// SWR infere Data do tipo de retorno do fetcher
const fetchUser = (url: string): Promise<User> => fetch(url).then((r) => r.json());
const { data } = useSWR("/api/me", fetchUser);
// data: User | undefined - inferido de fetchUserTipagem de chave de array:
type FetcherArgs = [url: string, token: string];
const fetcher: Fetcher<User, FetcherArgs> = ([url, token]) =>
fetch(url, { headers: { Authorization: `Bearer ${token}` } }).then((r) => r.json());
const { data } = useSWR<User, Error, FetcherArgs>(
["/api/me", authToken],
fetcher
);Middleware tipado:
import { Middleware, SWRHook } from "swr";
const loggerMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
const result = useSWRNext(key, fetcher, config);
console.log(`SWR [${key}]:`, result.data);
return result;
};
};Configuração SWR tipada:
import type { SWRConfiguration } from "swr";
const defaultConfig: SWRConfiguration<User, Error> = {
revalidateOnFocus: false,
errorRetryCount: 3,
onSuccess: (data) => {
// data é tipado como User
console.log(data.name);
},
};as para segurança de tipo. useSWR<User> é melhor do que data as User.null), o tipo de dados permanece Data | undefined mesmo com suspense.Key aceita string, any[], null, undefined ou () => Key.undefined para data, mesmo quando você espera que ele seja carregado.res.json() retorna Promise<any> por padrão. Você deve fazer um cast: res.json() as Promise<User>. Este é um limite de confiança - a validação em tempo de execução não é realizada.useSWR, o TypeScript pode silenciosamente expandir para any. Sempre verifique se seus tipos estão alinhados.error é any por padrão se você não especificar o genérico Error. Sempre especifique-o para segurança de tipo: useSWR<Data, Error>.useSWR em um hook personalizado, o tipo de retorno é SWRResponse<Data, Error>. Importe-o para tipagem explícita.Middleware em vez de escrever a assinatura completa manualmente.| Abordagem | Prós | Contras |
|---|---|---|
| Genéricos explícitos em useSWR | Controle total, tipos claros | Verboso, alinhamento manual |
| Inferido do fetcher | Menos boilerplate | Fácil de retornar any acidentalmente |
| Hooks tipados personalizados | Encapsulado, reutilizável | Camada de abstração extra |
| Validação em tempo de execução (zod) | Segurança real em tempo de execução | Dependência extra, custo de desempenho |
const { data, error } = useSWR<User, Error>("/api/me", fetcher);
// data: User | undefined
// error: Error | undefinedAté três genéricos: useSWR<Data, Error, Key>.
Sim. Se o seu fetcher tiver um retorno tipado, o SWR inferirá Data dele:
const fetchUser = (url: string): Promise<User> =>
fetch(url).then((r) => r.json());
const { data } = useSWR("/api/me", fetchUser);
// data: User | undefined (inferido)res.json() sempre retorna Promise<any> em TypeScript. Você deve fazer um cast: res.json() as Promise<User>. Este é um limite de confiança -- o TypeScript não pode validar a forma em tempo de execução. Considere usar Zod para validação em tempo de execução.
import { Fetcher } from "swr";
const fetcher: Fetcher<User[], string> = (url) =>
fetch(url).then((r) => r.json());Fetcher<Data, Key> garante que o fetcher aceite o tipo de chave e retorne Promise<Data>.
useSWRMutation<Data, Error, Key, Arg>(key, mutationFn);Data: tipo de retorno da mutaçãoError: tipo de erroKey: o tipo da chave de cacheArg: o tipo do argumento passado para triggerO TypeScript pode silenciosamente expandir para any em vez de mostrar um erro de compilação. Sempre verifique se o tipo de retorno do seu fetcher está alinhado com o genérico Data que você passa para useSWR.
type FetcherArgs = [url: string, token: string];
const fetcher: Fetcher<User, FetcherArgs> = ([url, token]) =>
fetch(url, {
headers: { Authorization: `Bearer ${token}` },
}).then((r) => r.json());
const { data } = useSWR<User, Error, FetcherArgs>(
["/api/me", authToken],
fetcher
);Ao envolver useSWR em um hook personalizado, o tipo de retorno é SWRResponse<Data, Error>. Importe-o de swr para tipagem explícita do valor de retorno do seu hook personalizado.
import { Middleware, SWRHook } from "swr";
const myMiddleware: Middleware = (useSWRNext: SWRHook) => {
return (key, fetcher, config) => {
return useSWRNext(key, fetcher, config);
};
};Use a exportação do tipo Middleware em vez de escrever a assinatura completa manualmente.
Prefira sempre genéricos explícitos (useSWR<User>) a casts as (data as User). Genéricos fornecem segurança em tempo de compilação em todo o uso do hook, enquanto casts apenas silenciam o verificador de tipo em um ponto.
import type { SWRConfiguration } from "swr";
const config: SWRConfiguration<User, Error> = {
revalidateOnFocus: false,
onSuccess: (data) => {
console.log(data.name); // data é tipado como User
},
};Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥