import { mensagemDeErro } from './biblioteca.js'; /** * Parte 2 — Do callback à Promise. * * npx tsx src/02-callback-para-promise.ts * * O mesmo trabalho — ler um livro e contar seus empréstimos em aberto — * escrito duas vezes: no estilo de callback do Node antigo e com Promises. */ import { buscarLivro, contarEmprestimosAbertos, type Livro } from './biblioteca.js'; // --------------------------------------------------------------------------- // Estilo de callback: o resultado não volta, ele é entregue. // --------------------------------------------------------------------------- type Callback = (erro: Error | null, valor?: T) => void; /** Versão de `buscarLivro` no formato (erro, valor) do Node antigo. */ function buscarLivroCb(id: number, callback: Callback): void { buscarLivro(id).then( (livro) => callback(null, livro), (erro: unknown) => callback(erro instanceof Error ? erro : new Error(mensagemDeErro(erro))), ); } function contarEmprestimosCb(livroId: number, callback: Callback): void { contarEmprestimosAbertos(livroId).then( (total) => callback(null, total), (erro: unknown) => callback(erro instanceof Error ? erro : new Error(mensagemDeErro(erro))), ); } function fichaComCallback(id: number, callback: Callback): void { buscarLivroCb(id, (erro, livro) => { if (erro || !livro) { callback(erro ?? new Error('livro ausente')); return; } contarEmprestimosCb(livro.id, (erro2, total) => { if (erro2 || total === undefined) { callback(erro2 ?? new Error('total ausente')); return; } callback(null, `${livro.titulo} — ${total} empréstimo(s) em aberto`); }); }); } // --------------------------------------------------------------------------- // Com Promise: o resultado volta como valor, e o erro volta pelo mesmo canal. // --------------------------------------------------------------------------- function fichaComPromise(id: number): Promise { return buscarLivro(id).then((livro) => contarEmprestimosAbertos(livro.id).then( (total) => `${livro.titulo} — ${total} empréstimo(s) em aberto`, ), ); } // --------------------------------------------------------------------------- fichaComCallback(1, (erro, ficha) => { console.log('callback :', erro ? `erro: ${erro.message}` : ficha); }); void fichaComPromise(1).then((ficha) => { console.log('promise :', ficha); }); /** * As duas versões fazem o mesmo. A diferença está em quem controla o quê: * * - No estilo de callback, `fichaComCallback` **entrega** a continuação do * programa para `buscarLivroCb` e torce para que ela seja chamada uma vez * só, com os argumentos certos. Isso é a inversão de controle. * - Com Promise, a função **devolve** um valor futuro. Quem chamou decide o * que fazer com ele, quando, e é livre para passá-lo adiante. * * O aninhamento é o sintoma visível; a inversão de controle é a causa. */