Desafio TypeScript

Sistema de biblioteca com tipos e readonly

Enunciado

Crie um type alias Livro com:

  • isbn: string (readonly)
  • titulo: string
  • autor: string
  • anoPublicacao: number (opcional)
  • disponivel: boolean (opcional, padrão true)

Crie um type alias Biblioteca que seja um array de Livro.

Implemente as funções:

  • adicionarLivro(biblioteca: Biblioteca, livro: Livro): Biblioteca — retorna uma nova biblioteca com o livro adicionado (não modifique o array original).
  • buscarLivroPorIsbn(biblioteca: Biblioteca, isbn: string): Livro | undefined — retorna o livro com o ISBN correspondente ou undefined.
  • listarLivrosDisponiveis(biblioteca: Biblioteca): string[] — retorna um array com os títulos dos livros disponíveis (considerando disponivel padrão true).

Teste criando uma biblioteca, adicionando livros, buscando por ISBN e listando disponíveis.

Requisitos

  • Definir os tipos Livro e Biblioteca conforme especificado.
  • isbn deve ser readonly.
  • adicionarLivro deve retornar um novo array (imutabilidade).
  • buscarLivroPorIsbn deve retornar Livro | undefined.
  • listarLivrosDisponiveis deve considerar disponivel padrão true.

Código inicial

// Defina os tipos e implemente as funções

type Livro = {
  // complete aqui
};

type Biblioteca = Livro[];

function adicionarLivro(biblioteca: Biblioteca, livro: Livro): Biblioteca {
  // complete aqui
}

function buscarLivroPorIsbn(biblioteca: Biblioteca, isbn: string): Livro | undefined {
  // complete aqui
}

function listarLivrosDisponiveis(biblioteca: Biblioteca): string[] {
  // complete aqui
}

// Testes
let minhaBiblioteca: Biblioteca = [];
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '123', titulo: 'Livro A', autor: 'Autor X' });
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '456', titulo: 'Livro B', autor: 'Autor Y', disponivel: false });
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '789', titulo: 'Livro C', autor: 'Autor Z', anoPublicacao: 2020 });

console.log(buscarLivroPorIsbn(minhaBiblioteca, '456'));
console.log(listarLivrosDisponiveis(minhaBiblioteca));

Saída esperada

{ isbn: '456', titulo: 'Livro B', autor: 'Autor Y', disponivel: false }
[ 'Livro A', 'Livro C' ]
Ver dica

Use readonly em isbn. Para adicionarLivro, use spread operator: [...biblioteca, livro]. Para disponivel, verifique se é undefined e assuma true.

Mostrar solução
type Livro = {
  readonly isbn: string;
  titulo: string;
  autor: string;
  anoPublicacao?: number;
  disponivel?: boolean;
};

type Biblioteca = Livro[];

function adicionarLivro(biblioteca: Biblioteca, livro: Livro): Biblioteca {
  return [...biblioteca, livro]; // novo array, não modifica o original
}

function buscarLivroPorIsbn(biblioteca: Biblioteca, isbn: string): Livro | undefined {
  return biblioteca.find(livro => livro.isbn === isbn);
}

function listarLivrosDisponiveis(biblioteca: Biblioteca): string[] {
  return biblioteca
    .filter(livro => livro.disponivel ?? true) // padrão true se undefined
    .map(livro => livro.titulo);
}

// Testes
let minhaBiblioteca: Biblioteca = [];
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '123', titulo: 'Livro A', autor: 'Autor X' });
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '456', titulo: 'Livro B', autor: 'Autor Y', disponivel: false });
minhaBiblioteca = adicionarLivro(minhaBiblioteca, { isbn: '789', titulo: 'Livro C', autor: 'Autor Z', anoPublicacao: 2020 });

console.log(buscarLivroPorIsbn(minhaBiblioteca, '456'));
console.log(listarLivrosDisponiveis(minhaBiblioteca));

Passo a passo

  1. Definimos Livro com isbn readonly, titulo e autor obrigatórios, e anoPublicacao e disponivel opcionais.
  2. Biblioteca é um alias para Livro[].
  3. adicionarLivro usa spread operator para criar um novo array com o livro adicionado, preservando a imutabilidade.
  4. buscarLivroPorIsbn usa Array.find para localizar o livro pelo ISBN, retornando Livro | undefined.
  5. listarLivrosDisponiveis filtra livros onde disponivel é true ou undefined (usando ?? true), e mapeia para os títulos.
  6. Nos testes, criamos uma biblioteca vazia, adicionamos três livros e chamamos as funções.
  7. Imprimimos o resultado da busca e a lista de disponíveis.

Por que funciona

O type alias Livro garante que cada objeto tenha a forma correta, com isbn imutável. As funções operam de forma pura: adicionarLivro não modifica o array original, buscarLivroPorIsbn retorna undefined se não encontrar, e listarLivrosDisponiveis trata a propriedade opcional disponivel com valor padrão. Isso demonstra o uso combinado de tipos de objeto, propriedades opcionais, readonly e type aliases.

Erros comuns

  • Modificar o array original: usar biblioteca.push(livro) em vez de retornar novo array. Isso quebra a imutabilidade e pode causar efeitos colaterais.
  • Esquecer readonly em isbn: se não usar, o ISBN pode ser alterado, contrariando o requisito.
  • Não tratar disponivel como opcional: se fizer livro.disponivel === true, livros sem a propriedade não aparecerão na lista. Use ?? true ou verifique undefined.
  • Retornar tipo errado em buscarLivroPorIsbn: se não declarar Livro | undefined, o TypeScript pode inferir Livro e causar erro ao retornar undefined.

Outra forma de resolver

Para listarLivrosDisponiveis, poderia usar um loop for com if:

const titulos: string[] = [];
for (const livro of biblioteca) {
  if (livro.disponivel !== false) {
    titulos.push(livro.titulo);
  }
}
return titulos;

É mais verboso, mas pode ser mais legível para iniciantes. A versão com filter e map é mais idiomática em TypeScript.

Saída esperada

{ isbn: '456', titulo: 'Livro B', autor: 'Autor Y', disponivel: false }
[ 'Livro A', 'Livro C' ]