Vale a pena migrar? Descubra se o Flow para usuários de TypeScript em 2026 faz sentido. Compare segurança de tipagem, opaque types e performance no projeto.
Se você já usa TypeScript e está curioso sobre o Flow, ou se precisa decidir entre os dois em 2026, este artigo é para você. Vamos comparar as duas ferramentas de tipagem para JavaScript, com foco no que o Flow oferece de diferente — e em como ele pode surpreender positivamente quem vem do TypeScript.
Atenção: Este texto não é uma batalha de “qual é melhor”. É um guia de transição conceitual, mostrando equivalentes e diferenças práticas.
1. Filosofia: soundness vs. pragmatismo
A diferença mais fundamental está na soundness (solidez) do sistema de tipos.
-
TypeScript foi projetado para ser um type system pragmático. Ele prioriza a adoção fácil e a compatibilidade com o ecossistema JavaScript existente. Muitas operações que parecem seguras são permitidas, mesmo que possam causar erros em tempo de execução (ex.:
anyimplícito, indexação de objetos sem verificação de existência da chave). -
Flow tem uma abordagem mais sound (sólida). Ele tenta ativamente evitar falsos negativos, ou seja, situações em que o verificador de tipos diz que está tudo bem, mas um erro ocorre em runtime. Para isso, faz análises mais profundas (como flow-sensitive typing avançado, rastreamento de null e void rigoroso, e controle refinado de refinements).
Na prática:
-
Em Flow, você encontrará mensagens de erro mais restritivas em cenários onde o TypeScript poderia simplesmente deixar passar. Para muitos times, isso significa uma segurança maior, mas exige uma curva de aprendizado um pouco mais íngreme na modelagem de tipos complexos.
2. Sintaxe de tipos: muito similar, mas com algumas divergências
A sintaxe de anotações de tipo em Flow é quase idêntica à do TypeScript. Se você sabe anotar variáveis, funções e interfaces em TS, vai se sentir em casa.
Exemplo comum:
// TypeScript function greet(name: string): string { return `Hello, ${name}`; }
// Flow function greet(name: string): string { return `Hello, ${name}`; }
Porém, há diferenças em:
-
Type aliases e interfaces: Flow usa
typeeinterfacede forma muito similar, mas a palavra-chaveinterfaceem Flow funciona mais como um type estrutural, sem a fusão de declarações (declaration merging) que o TypeScript tem. -
Enums: Flow não possui
enum. Em vez disso, você usa uniões de literais ou opaque types com objetos congelados. A filosofia do Flow é que enums do TypeScript introduzem código em tempo de execução, o que quebra a premissa de que tipos são apenas para verificação estática. -
Namespaces e módulos: Flow não tem
namespace(legacy). A organização de código é puramente via módulos ES (import/export). Se você usa namespaces no TypeScript, precisará migrar para módulos para usar Flow.
3. Inferência de tipos e type narrowing
O Flow sempre foi elogiado pelo seu controle de fluxo (flow-sensitive typing). O TypeScript evoluiu muito nesse aspecto, mas o Flow ainda oferece um refinamento mais granular em alguns casos.
Exemplo: refinamento com typeof e condicionais
function process(value: string | number) { if (typeof value === 'string') { // value é refinado para string automaticamente console.log(value.toUpperCase()); } else { // aqui value é number console.log(value.toFixed(2)); } }
Até aqui, TypeScript se comporta igual. A diferença aparece em refinamento de propriedades de objetos após verificações de existência, especialmente com strict mode.
Refinamento com hasOwnProperty ou checagem de campo:
No Flow, uma checagem como if (obj.prop !== undefined) refina o tipo de obj.prop e também pode influenciar o tipo de obj como um todo, de maneira mais agressiva. Isso é útil em tagged unions (uniões discriminadas).
Exemplo com tagged union (TypeScript e Flow são parecidos):
type Result = | { status: 'ok', data: string } | { status: 'error', message: string }; function handle(result: Result) { if (result.status === 'ok') { console.log(result.data); // OK } else { console.log(result.message); // OK } }
Ambos funcionam bem. O Flow pode ser mais estrito na análise de exaustividade e em casos com switch ou if/else aninhados.
4. Tipos opacos (opaque types) – a grande vantagem do Flow
O Flow introduz o conceito de opaque types, que são tipos nominais dentro de um sistema estrutural. Isso permite criar tipos que não são intercambiáveis mesmo que tenham a mesma estrutura subjacente.
Por que isso importa? Em TypeScript, você pode simular isso com branding (ex.: type UserID = string & { __brand: 'UserID' }), mas é um truque que exige atenção. Em Flow, é nativo e muito mais simples:
opaque type UserID = string; opaque type OrderID = string; function getUser(id: UserID): User { ... } function getOrder(id: OrderID): Order { ... } // Exemplo de uso: const uid: UserID = "123"; // precisa ser criado com uma função que retorne o tipo opaco const oid: OrderID = "456"; getUser(uid); // OK getUser(oid); // Erro! OrderID não é atribuível a UserID
Isso evita confusão entre identificadores de entidades diferentes – algo comum em bases de código grandes. TypeScript não tem equivalente direto (fora os workarounds com brand).
5. Utility types e manipulação de tipos
O TypeScript tem uma gama enorme de utility types embutidos (Partial, Required, Pick, Omit, ReturnType, etc.). O Flow também possui vários, mas a cobertura é ligeiramente diferente.
Equivalências aproximadas (Flow para TS):
| Flow | TypeScript |
|---|---|
$Keys<T> |
keyof T |
$Values<T> |
T[keyof T] |
$ReadOnly<T> |
Readonly<T> |
$Shape<T> |
Partial<T> (mas com nuances) |
$Diff<A, B> |
Omit<A, keyof B> |
$Rest<A, B> |
Pick<A, keyof B>? (não exato) |
$Exact<T> |
Sem equivalente direto (exige fidelidade de forma exata) |
$Call<F> |
ReturnType<F> |
Class<T> |
Tipo da instância da classe |
Uma diferença relevante: $Exact<T> garante que um objeto tenha exatamente as propriedades especificadas, sem campos extras. TypeScript lida com excess property checking apenas em atribuições diretas e literais, mas não como um tipo reutilizável. Em Flow, {| prop: string |} é a sintaxe para exact objects.
Exemplo:
type User = {| name: string, age: number |}; const u: User = { name: "Ana", age: 30, extra: true }; // Erro! 'extra' não existe em User
6. TypeScript tem as const – Flow tem literais e $ReadOnly
Em TypeScript, as const infere o tipo mais específico de um literal e o torna readonly. Em Flow, você pode conseguir algo similar usando $ReadOnly e anotação explícita, mas a inferência de tipos literais já é profunda.
const colors = ['red', 'green', 'blue'] as const; // TS // Em Flow, você pode fazer: const colors: $ReadOnlyArray<'red' | 'green' | 'blue'> = ['red', 'green', 'blue'];
Mas a inferência muitas vezes resolve sozinha se você usar Object.freeze e anotações.
7. Integração com React
Flow tem suporte de primeira classe a React (vem da mesma empresa – Meta). A sintaxe para componentes é idêntica à do TypeScript (com React.FC ou anotações de props diretamente).
Componente funcional em Flow:
type Props = { name: string, age?: number, }; function Greeting({ name, age }: Props): React.Node { return <div>Hello {name}, you are {age ?? 'unknown'} years old</div>; }
O Flow também tem tipos específicos como React.Element<typeof Component>, React.ChildrenArray, etc., que são muito similares aos do TypeScript (@types/react).
8. Ecossistema e suporte a bibliotecas
O TypeScript tem uma vantagem massiva em definições de tipo da comunidade: DefinitelyTyped e tipagem nativa de milhares de pacotes. O Flow depende do flow-typed, que é menos abrangente e frequentemente desatualizado. Em 2026, ainda é o maior ponto de atrito para quem adota Flow: você pode precisar escrever declarações de tipo para bibliotecas de terceiros.
Para projetos com poucas dependências externas ou que usam majoritariamente bibliotecas do ecossistema Meta (React, Jest, etc.), isso não é um problema. Mas se você depende de muitas libs do npm, TypeScript pode ser mais produtivo.
9. Performance e escalabilidade
O Flow foi reescrito em Rust e é reconhecido por ser muito rápido na verificação de tipos, especialmente em bases de código enormes (a Meta tem milhões de linhas de JS). O TypeScript também melhorou bastante, mas ainda é implementado em TypeScript/JavaScript e pode ser mais lento em projetos gigantes.
Se o tempo de verificação de tipos é crítico no seu CI, Flow pode oferecer uma diferença perceptível. Por outro lado, o suporte de IDEs (VSCode) para TypeScript é mais polido e integrado, enquanto para Flow você precisa de extensão oficial e pode haver pequenas latências.
10. Conclusão: quando escolher Flow em 2026?
Considere Flow se:
-
Você valoriza um sistema de tipos mais sound e está disposto a modelar com mais exatidão.
-
Você faz uso intenso de opaque types (identificadores nominais) e exact objects.
-
Sua base de código é enorme e a velocidade do verificador é prioridade.
-
Seu projeto é focado em React e tem poucas dependências externas não tipadas.
Fique com TypeScript se:
-
Você precisa do ecossistema vasto de tipos da comunidade e suporte a qualquer biblioteca.
-
Quer menor barreira de entrada e maior quantidade de recursos educacionais.
-
Faz uso extensivo de padrões como
enum,namespaceou declaration merging que não têm equivalente direto no Flow.
Ambos são excelentes. A escolha em 2026 continua sendo uma questão de contexto e preferências de modelagem.
Este artigo foi baseado nesta documentação: https://flow.org/en/docs/flow-vs-typescript/
Continue a aprender
Curtiu dar esse mergulho no universo da tipagem do JavaScript? Se você tá afim de deixar a arquitetura do seu ecossistema de desenvolvimento ainda mais parruda e produtiva, dá um confere nesses artigos:
- Como gerar tipos TypeScript direto do PostgreSQL com Kanel
Esquece aquele trabalho braçal de “sincronizador humano” de tipos. Automatize o tédio e garanta que sua base de dados seja a única fonte da verdade, com type safety estrito pro seu projeto não capotar. - Adeus, VS Code? Por Que o Cursor AI Virou o Favorito dos Devs
Se liga nessa ferramenta que tá mudando o fluxo de trabalho. Descubra como codar com uma IA integrada que entende o contexto de todo o repositório para refatorar sem dor de cabeça. - Extensões PostgreSQL: Substitua Redis, MongoDB e Kafka com SQL
Aumente a eficiência consolidando sua stack. Veja quando faz sentido e até onde o Postgres aguenta o tranco pesado na arquitetura do backend.

