ts-pattern para TypeScript: guia completo com exemplos
A biblioteca ts-pattern traz para o TypeScript um mecanismo poderoso e expressivo de pattern matching (correspondência de padrões), inspirado em linguagens como OCaml, Rust, Haskell e Scala. Em vez de longas cadeias de if-else ou switch-case, o ts-pattern permite descrever a lógica de ramificação de forma declarativa, verificando a estrutura e os tipos dos dados. Isso é especialmente valioso ao trabalhar com tipos de dados algébricos (ADTs), como discriminated unions (uniões discriminadas), valores opcionais (Option) ou resultados (Result).
Por que usar isso? Primeiro, o código se torna mais legível e conciso. Em vez de analisar objetos aninhados complexos com várias verificações, você descreve a estrutura de dados desejada e a biblioteca encontra a opção correspondente. Segundo, o ts-pattern garante uma verificação de exaustividade (exhaustiveness check): se você não tratar todos os casos possíveis, o TypeScript emitirá um erro em tempo de compilação. Isso reduz drasticamente a quantidade de bugs relacionados a estados não tratados. Terceiro, a biblioteca é totalmente tipada e se integra ao sistema de tipos do TypeScript, tornando a refatoração segura e previsível.
O ts-pattern não é apenas um substituto para o switch. É uma ferramenta completa para decomposição de dados, que permite corresponder não apenas valores, mas também seus tipos, estruturas, intervalos e até predicados personalizados. A biblioteca é amplamente utilizada em projetos onde a confiabilidade e a expressividade são importantes: desde aplicações front-end com React/Redux até serviços back-end com Node.js.
Instalação
A instalação da biblioteca é feita através do gerenciador de pacotes npm (ou yarn/pnpm). Certifique-se de que seu projeto use TypeScript versão 4.0 ou superior.
npm install ts-pattern
Após a instalação, a biblioteca está pronta para uso. Nenhuma configuração adicional no tsconfig.json é necessária.
Início rápido
Vamos começar com um exemplo clássico: o tratamento do resultado de uma requisição HTTP. Imagine que temos uma união discriminada (discriminated union) que descreve o estado do carregamento de dados.
import { match } from 'ts-pattern';
// Definindo os estados possíveis
type State =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
// Função que retorna um texto dependendo do estado
function getStatusMessage(state: State): string {
return match(state)
.with({ status: 'idle' }, () => 'Aguardando...')
.with({ status: 'loading' }, () => 'Carregando...')
.with({ status: 'success' }, ({ data }) => `Dados: ${data}`)
.with({ status: 'error' }, ({ error }) => `Erro: ${error.message}`)
.exhaustive(); // verifica se todos os casos foram tratados
}
// Exemplos de uso
console.log(getStatusMessage({ status: 'idle' })); // "Aguardando..."
console.log(getStatusMessage({ status: 'loading' })); // "Carregando..."
console.log(getStatusMessage({ status: 'success', data: 'Olá, mundo!' })); // "Dados: Olá, mundo!"
console.log(getStatusMessage({ status: 'error', error: new Error('404') })); // "Erro: 404"
Este exemplo demonstra a ideia principal: combinamos o objeto state com diferentes padrões. Cada padrão é uma descrição parcial da estrutura do objeto. Se a estrutura corresponder, a função associada é executada. O método .exhaustive() garante que nenhum dos casos foi esquecido.
Principais métodos e funções
A biblioteca oferece várias funções e métodos essenciais. Vamos detalhá-los.
1. match(value)
Assinatura: match<I, O>(value: I): Match<I, O>
O que faz:
Também na biblioteca
Trabalhando com Apache Kafka em C# (.NET): biblioteca Confluent.Kafka
Processamento e edição de imagens em TypeScript: Jimp, Sharp, Canvas