Como deixar o postMessage type-safe em menos de 350 bytes
Aprofundamento CEVIU
Aprofundamento
O typed-channel separa duas responsabilidades: o transport move a mensagem pela fronteira, e o channel sabe quais mensagens existem e o que cada uma carrega. Você declara os tipos uma vez, em dois type maps (um por direção), e o TypeScript checa emit e on dos dois lados. Um typo como "generated:colors" no lugar de "generated:color" deixa de compilar. O on devolve uma função de remoção do listener, o que elimina a necessidade de guardar a referência do handler para o removeEventListener.
O núcleo tem 271 bytes minificado e com Brotli, e 341 bytes com o transport de postMessage, sem dependências. O transport é só um objeto com duas funções, on e emit, então dá para escrever um para Figma plugin (figma.ui.postMessage de um lado, parent.postMessage({ pluginMessage }) do outro) em cerca de uma dúzia de linhas. Um channel também aceita vários transports ao mesmo tempo, por exemplo EventTarget e BroadcastChannel, e um emit chega na aba atual e nas demais.
A versão 0.11 traz o createTypedRpcChannel, com request e handle. Cada request é tipado como função: o parâmetro é o payload, e o retorno é a resposta, escrita como valor simples (GeneratedColor[]) e não como promise. Se o handler lançar erro, a promise do chamador rejeita. Não há opção de timeout: o request aceita um AbortSignal, e AbortSignal.timeout(5000) cobre esse caso. Abortar rejeita a promise e manda uma mensagem de abort ao outro lado, que aborta o signal recebido pelo handler. O worker para o trabalho em vez de terminar para ninguém.
Por que isso importa
Para quem mantém worker, iframe ou plugin no mesmo projeto, a leitura é que o contrato de mensagens sai dos switch espalhados e vira tipo. Isso reduz bug de typo e de listener vazado. O cancelamento propagado também evita trabalho inútil no worker quando o usuário já saiu da tela. Como as mensagens ficam em 271 bytes e o RPC (1 kB) é importado à parte, dá para adotar só o que você precisa.
Perguntas frequentes
Quanto o typed-channel pesa no bundle?
O núcleo tem 271 bytes minificado e com Brotli. Com o transport de postMessage, chega a 341 bytes. O createTypedRpcChannel, que inclui tudo, tem 1 kB e é importado separadamente.
O que a versão 0.11 do typed-channel adicionou?
Adicionou requests, pelo createTypedRpcChannel. Cada request tem resposta tipada e aceita um AbortSignal. Ao abortar, o handler do outro lado também é interrompido, e erros lançados nele rejeitam a promise do chamador.
O typed-channel valida payloads em runtime?
Não. A biblioteca não valida o payload nem o resultado, que são clonados estruturadamente do jeito que você passa. O requests() também não tem custo em runtime, só repassa os mapas para o TypeScript inferir os tipos.
Como definir timeout em um request?
Passe um AbortSignal.timeout, por exemplo AbortSignal.timeout(5000). Um request sem handler do outro lado nunca resolve sozinho e só termina pelo signal. Se o par pode não estar pronto, use um signal de timeout.
Fontes
- evilmartians.comfonte original
- Categoria
- CEVIU Web Dev
- Publicado
- 29 de outubro de 2026
- Editoria
- CEVIU Web Dev

