3

Pitch: is-kit vs Zod: uma comparação prática sob 3 perspectivas

Olá, pessoal!

Sou engenheiro frontend e, às vezes, me pergunto:

Sou eu que estou usando a IA… ou é a IA que está me usando?

Quando precisamos escrever validações em runtime no TypeScript, o Zod geralmente é uma das primeiras opções que vêm à mente.

Existem outras alternativas, como Valibot e ArkType, mas hoje quero falar sobre algo um pouco diferente:

is-kit

O is-kit é um toolkit leve e sem dependências para criar type guards reutilizáveis em TypeScript.

Ele permite criar pequenas funções no estilo isFoo, combiná-las para construir verificações mais completas em runtime e manter o narrowing de tipos integrado ao fluxo de controle normal do TypeScript.

É seguro em runtime, composable e simples de usar, sem exigir a adoção de um sistema completo baseado em schemas.

Com ele, você pode:

  • criar e reutilizar type guards tipados;
  • combinar guards usando and, or, not e oneOf;
  • validar estruturas de objetos e coleções;
  • interpretar ou verificar valores unknown sem utilizar um framework de schemas maior.

À primeira vista, is-kit e Zod podem parecer semelhantes.

Porém, suas filosofias de design são bem diferentes:

  • is-kit → um toolkit para combinar type guards;
  • Zod → uma biblioteca para definir schemas e validar dados.

Em vez de perguntar “qual é melhor?”, vamos compará-los de uma perspectiva prática:

Em quais situações cada um é mais simples de escrever?

Vamos analisar três aspectos:

  • tamanho do código;
  • legibilidade;
  • tratamento dos tipos.

O mesmo exemplo

Vamos validar um objeto User simples.

is-kit

import {
  and,
  isInteger,
  isString,
  oneOfValues,
  optionalKey,
  predicateToRefine,
  safeParse,
  struct,
} from "is-kit";

const isPositiveInt = and(
  isInteger,
  predicateToRefine<number>((v) => v > 0),
);

const isUser = struct({
  id: isPositiveInt,
  name: isString,
  role: oneOfValues(["admin", "member"] as const),
  nickname: optionalKey(isString),
});

const result = safeParse(isUser, input);

if (result.valid) {
  result.value.role;
}

Zod

import { z } from "zod";

const UserSchema = z.object({
  id: z.number().int().positive(),
  name: z.string(),
  role: z.enum(["admin", "member"]),
  nickname: z.string().optional(),
});

const result = UserSchema.safeParse(input);

if (result.success) {
  result.data.role;
}

Já podemos observar a principal diferença:

  • is-kit → combina pequenos guards baseados em funções;
  • Zod → define um schema de maneira declarativa.

1. Tamanho do código

O código com Zod frequentemente parece mais curto.

Por quê?

Porque é possível encadear várias restrições em um único lugar:

z.string().min(1).max(20).regex(...)
z.number().int().positive()

Esse modelo funciona muito bem para:

  • formulários;
  • validação de APIs;
  • validação nas fronteiras de entrada da aplicação.

Por outro lado, o is-kit se destaca quando queremos reutilizar os mesmos guards em diferentes partes da lógica:

if (isUser(value)) {
  // O tipo já foi refinado
}

const users = values.filter(isUser);

Os guards podem ser utilizados diretamente no fluxo de controle do TypeScript.

Com Zod, geralmente passamos por métodos como safeParse, então a operação se parece mais com uma chamada explícita de validação.

Resumo

  • Quer regras de validação centralizadas → Zod;
  • Quer guards reutilizáveis dentro da lógica → is-kit.

2. Legibilidade

Isso depende do que consideramos “legível”.

Zod

Todas as regras ficam concentradas em um único lugar:

const UserSchema = z.object({ ... });

É possível entender imediatamente:

Qual estrutura de dados é considerada válida?

Isso funciona muito bem nas fronteiras da aplicação.

is-kit

O is-kit se parece mais com o fluxo de controle normal do TypeScript.

Também é possível combinar e refinar os guards gradualmente:

import { hasKey, narrowKeyTo } from "is-kit";

const hasRole = hasKey("role");

if (hasRole(value)) {
  value.role;
}

const byRole = narrowKeyTo(isUser, "role");
const isAdmin = byRole("admin");

if (isAdmin(value)) {
  value.role;
  value.name;
}

Nesse exemplo, podemos:

  1. refinar toda a estrutura usando isUser;
  2. focar em uma propriedade específica, como role;
  3. refinar ainda mais o valor para admin.

Esse modelo combina naturalmente com o seguinte fluxo:

Receber um valor unknown → refiná-lo passo a passo.

Resumo

  • Quer uma especificação clara dos dados válidos → Zod;
  • Quer narrowing integrado ao fluxo de controle → is-kit.

3. Como os tipos são tratados

É aqui que aparece a maior diferença entre as duas abordagens.

Zod: Schema → Tipo

type User = z.infer<typeof UserSchema>;

O fluxo é:

  1. definir o schema;
  2. gerar o tipo a partir dele.

Essa abordagem funciona muito bem quando queremos:

Manter a validação e os tipos definidos em um único lugar.

is-kit: Guard → Narrowing

O is-kit se concentra principalmente no fluxo de controle:

if (isUser(input)) {
  input.role;
}

O TypeScript refina automaticamente o tipo de input.

Também é possível extrair o tipo correspondente ao guard:

import type { GuardedOf } from "is-kit";

type User = GuardedOf<typeof isUser>;

No entanto, a principal vantagem do is-kit não é a geração de tipos.

É isto:

O TypeScript entende a lógica enquanto refinamos os valores.

Diferença central

  • Zod → forte no fluxo schema → tipo;
  • is-kit → forte no fluxo guard → narrowing dentro do controle da aplicação.

Resumo da comparação

PerspectivaZodis-kit
Tamanho do códigoExcelente para schemasExcelente para reutilização
LegibilidadeRegras de validação centralizadasFluxo de controle natural
Tratamento dos tiposTipos derivados de schemasNarrowing baseado no fluxo de controle

Quando usar cada um

Minha abordagem pessoal é:

Use Zod para entradas externas

Por exemplo:

  • respostas de APIs;
  • formulários;
  • variáveis de ambiente.

Use is-kit para a lógica interna

Por exemplo:

  • ramificações condicionais;
  • filtragem de arrays;
  • composição de type guards.

Eles não são concorrentes diretos

Essas ferramentas não precisam competir entre si.

Na verdade, elas podem funcionar muito bem juntas.

Uma separação clara seria:

  • Zod → validar dados nas fronteiras da aplicação;
  • is-kit → refinar valores dentro da aplicação.

Conclusão

O is-kit não é uma versão mais leve do Zod.

Ele se concentra em outra ideia:

Fazer com que type guards pareçam uma parte natural do TypeScript.

O Zod, por outro lado, continua sendo extremamente poderoso para:

Validação schema-first com segurança de tipos.

Portanto, a pergunta principal não é:

Qual deles é melhor?

Mas sim:

Em qual parte da arquitetura você quer garantir a segurança dos tipos?

Caso tenha interesse, você pode conhecer o projeto aqui:

Carregando publicação patrocinada...