Tell us what’s happening:
Hi! So I am stuck, I can’t figure out why I keep getting the errors I am. I am trying to access the properties in “products” and I keep getting the errors like product.item, product.type or product.title don’t exist on type "Product & Item for example. Any help is appreciated!
Your code so far
<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Product Showcase</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Product Showcase</h1>
<div class="buttons">
<button id="all">All</button>
<button id="books">Books</button>
<button id="electronics">Electronics</button>
<button id="clothing">Clothing</button>
</div>
<div id="output" class="product-list"></div>
<script src="index.ts"></script>
</body>
</html>
/* file: styles.css */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0f4c75 0%, #3282b8 100%);
padding: 40px 20px;
margin: 0;
color: #1a1a1a;
min-height: 100vh;
}
h1 {
text-align: center;
margin-bottom: 40px;
color: #ffffff;
font-size: 2.5rem;
font-weight: 600;
letter-spacing: -0.5px;
}
.buttons {
display: flex;
justify-content: center;
gap: 12px;
margin-bottom: 40px;
flex-wrap: wrap;
}
button {
padding: 12px 24px;
font-size: 15px;
font-weight: 500;
cursor: pointer;
border: none;
border-radius: 8px;
background: rgba(255, 255, 255, 0.9);
color: #333;
transition: all 0.3s ease-in-out;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
button:hover {
background: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
button.active {
background: #ff9800;
color: #1a1a1a;
box-shadow: 0 4px 15px rgba(255, 152, 0, 0.4);
font-weight: 600;
}
#output {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
max-width: 1200px;
margin: 0 auto;
}
.item {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease-in-out;
display: flex;
flex-direction: column;
gap: 12px;
}
.item:hover {
transform: translateY(-8px);
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.15);
}
.item strong {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 1px;
color: #0f4c75;
font-weight: 700;
}
.item > div:not(.price) {
font-size: 16px;
color: #555;
line-height: 1.5;
}
.price {
margin-top: auto;
font-size: 24px;
font-weight: 700;
color: #0f4c75;
padding-top: 12px;
border-top: 2px solid #f0f0f0;
}
@media (max-width: 768px) {
#output {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
h1 {
font-size: 2rem;
}
.item {
padding: 16px;
}
}
@media (max-width: 480px) {
#output {
grid-template-columns: 1fr;
}
button {
padding: 10px 16px;
font-size: 14px;
}
.price {
font-size: 20px;
}
}
/* file: index.ts */
interface Item {
type: "book" | "electronics" | "clothing";
id: string;
price: number;
};
interface Book extends Item {
type: "book";
title: string;
author: string;
};
interface Electronics extends Item {
type: "electronics";
item: string;
model: string;
warranty?: number;
};
interface Clothing extends Item {
type: "clothing";
item: string;
brand: string;
size?: "S" | "M" | "L";
};
type Product = Book | Electronics | Clothing
class Collection<T>{
private items: Array<T>;
constructor(i: Array<T>) {
this.items = i
}
getAll() {
// console.log(this.items)
return this.items
}
filter(callback: (item: T) => boolean): T[]{
return this.items.filter(callback)
}
}
const products = new Collection<Product>([
{
type: "book",
id: "b1",
price: 13.99,
title: "LOTR Fellowship of the Ring",
author:"JRR Tolkien"
},
{
type: "book",
id: "b2",
price: 12.99,
title: "The Hobbit",
author: "JRR Tolkien"
},
{
type: "clothing",
id: "c1",
price: 34.59,
item: "Hoodie",
brand: "thisbrand",
size: "S"
},
{
type: "electronics",
id: "e1",
price: 57.32,
item: "headphones",
model: "T32",
warranty: 2
},
{
type: "clothing",
id: "c2",
price: 45.34,
item: "Sweater",
brand: "thisbrand",
size: "L"
},
{
type: "electronics",
id: "e2",
price: 189.13,
item: "Microphone",
model: "3Ef2Q22",
warranty: 0
}])
const allItems = products.getAll()
const books = products.filter((item) => item.type === 'book')
const clothing = products.filter((item) => item.type === 'clothing')
const electronics = products.filter((item) => item.type === 'electronics')
const all = document.querySelector<HTMLButtonElement>("#all")
const allBooks = document.querySelector<HTMLButtonElement>("#books")
const allClothing = document.querySelector<HTMLButtonElement>("#clothing")
const allElectronics = document.querySelector<HTMLButtonElement>("#electronics")
const output = document.querySelector<HTMLElement>("#output")
function showProducts () {
if(output) output.innerHTML = renderProduct(products.getAll())
if(all){
all.addEventListener("click", () => {
return renderProduct(allItems)
})
}
if(allClothing){
return allClothing.addEventListener("click", () => renderProduct(clothing));
}
if(allBooks){
return allBooks.addEventListener("click",() => renderProduct(books));
}
if(allElectronics){
return allElectronics.addEventListener("click", () => renderProduct(electronics));
}
}
const isValid = (product: unknown): product is Item => {
return !!product && typeof product === "object" && "type" in product && "id" in product && "price" in product
}
console.log(isValid(allItems))
function renderProduct (product: Product[]):string {
let itemProperties = '';
if(isValid(product)){
if(product.type === "book"){
itemProperties += `<div class="item" id="${product.id}">
<p><strong>Book:</strong> ${product.title} by ${product.author}</p>
<p class="price">$${product.price}</p>
</div>`
}
if(product.type === "clothing"){
itemProperties += `<div class="item" id="${product.id}">
<p><strong>Clothing:</strong> ${product.item} by ${product.brand}</p>
<p class="price">$${product.price}</p>
</div>`
}
if(product.type === "electronics"){
itemProperties += `<div class="item" id="${product.id}">
<p><strong>Clothing:</strong> ${product.item} by ${product.model}</p>
<p class="price">$${product.price}</p>
</div>`
}
}
return itemProperties
}
document.addEventListener("DOMContentLoaded", () => {
showProducts()
})
Your browser information:
User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36
Challenge Information:
Build a Product Showcase - Build a Product Showcase