Опишите общие price/category через generic-ограничение, чтобы сохранить дополнительные поля товаров. Суммируйте обычные цены и цены после скидки категории; результат примера — 40 и 32.
Подсчёт полной стоимости товаров с учётом скидок
Опишите общие price/category через generic-ограничение, чтобы сохранить дополнительные поля товаров. Суммируйте обычные цены и цены после скидки категории; результат примера — 40 и 32.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Дан массив объектов products. Требуется реализовать функцию calculateTotal, принимающую массив товаров и объект скидок discountPercentage. Функция должна вычислить суммарную стоимость всех товаров без применения скидок, а также стоимость с учётом скидок, и вернуть объект result, структура которого продемонстрирована в комментариях к коду. Решение должно быть написано на TypeScript.
const products = [
{ id: 1123, price: 20, name: 'apple', color: 'red', category: 'fruit' },
{ id: 4322, price: 20, name: 'apple', ferm: 'siberia', category: 'vegetable' },
];
function calculateTotal(products, discount) {}
const discountPercentage = { fruit: 10, vegetable: 30 };
const result = calculateTotal(products, discountPercentage);
console.log("receipt", result);
// "receipt", {
// "totalWithoutDiscount": 40,
// "totalWithDiscount": 32,
// "discount": {
// "fruit": 10,
// "vegetable": 30
// },
// "items": [
// {
// "id": 1123,
// "price": 20,
// "name": "apple",
// "color": "red",
// "category": "fruit"
// },
// {
// "id": 4322,
// "price": 20,
// "name": "apple",
// "ferm": "siberia",
// "category": "vegetable"
// }
// ]
// }
Ответ
Опишите общие price/category через generic-ограничение, чтобы сохранить дополнительные поля товаров. Суммируйте обычные цены и цены после скидки категории; результат примера — 40 и 32.
type Priced = { price: number; category: string };
function calculateTotal<T extends Priced>(products: readonly T[], discount: Record<string, number>) {
let full = 0, reduced = 0;
for (const item of products) {
const rate = Object.hasOwn(discount, item.category) ? discount[item.category] : 0;
if (!Number.isFinite(item.price) || item.price < 0 ||
!Number.isFinite(rate) || rate < 0 || rate > 100) throw new RangeError('Некорректные данные');
const cents = Math.round(item.price * 100);
full += cents;
reduced += Math.round(cents * (100 - rate) / 100);
}
return { totalWithoutDiscount: full / 100, totalWithDiscount: reduced / 100,
discount: { ...discount }, items: products.map(item => ({ ...item })) };
}
Товары не мутируют, color и ferm сохраняются. Здесь округление происходит по каждой позиции до копейки; для платёжной системы предпочтительны исходные целые копейки и явно ограниченный диапазон сумм.