diff --git a/src/homeworks/ts1/1_base.js b/src/homeworks/ts1/1_base.js deleted file mode 100644 index 611b3a92f..000000000 --- a/src/homeworks/ts1/1_base.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Нужно превратить файл в ts и указать типы аргументов и типы возвращаемого значения - * */ -export const removePlus = (string) => string.replace(/^\+/, ''); - -export const addPlus = (string) => `+${string}`; - -export const removeFirstZeros = (value) => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2'); - -export const getBeautifulNumber = (value, separator = ' ') => - value?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator); - -export const round = (value, accuracy = 2) => { - const d = 10 ** accuracy; - return Math.round(value * d) / d; -}; - -const transformRegexp = - /(matrix\(-?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, )(-?\d+(\.\d+)?), (-?\d+(\.\d+)?)\)/; - -export const getTransformFromCss = (transformCssString) => { - const data = transformCssString.match(transformRegexp); - if (!data) return { x: 0, y: 0 }; - return { - x: parseInt(data[6], 10), - y: parseInt(data[8], 10), - }; -}; - -export const getColorContrastValue = ([red, green, blue]) => - // http://www.w3.org/TR/AERT#color-contrast - Math.round((red * 299 + green * 587 + blue * 114) / 1000); - -export const getContrastType = (contrastValue) => (contrastValue > 125 ? 'black' : 'white'); - -export const shortColorRegExp = /^#[0-9a-f]{3}$/i; -export const longColorRegExp = /^#[0-9a-f]{6}$/i; - -export const checkColor = (color) => { - if (!longColorRegExp.test(color) && !shortColorRegExp.test(color)) throw new Error(`invalid hex color: ${color}`); -}; - -export const hex2rgb = (color) => { - checkColor(color); - if (shortColorRegExp.test(color)) { - const red = parseInt(color.substring(1, 2), 16); - const green = parseInt(color.substring(2, 3), 16); - const blue = parseInt(color.substring(3, 4), 16); - return [red, green, blue]; - } - const red = parseInt(color.substring(1, 3), 16); - const green = parseInt(color.substring(3, 5), 16); - const blue = parseInt(color.substring(5, 8), 16); - return [red, green, blue]; -}; - -export const getNumberedArray = (arr) => arr.map((value, number) => ({ value, number })); -export const toStringArray = (arr) => arr.map(({ value, number }) => `${value}_${number}`); - -export const transformCustomers = (customers) => { - return customers.reduce((acc, customer) => { - acc[customer.id] = { name: customer.name, age: customer.age, isSubscribed: customer.isSubscribed }; - return acc; - }, {}); -}; diff --git a/src/homeworks/ts1/1_base.test.js b/src/homeworks/ts1/1_base.test.js index ee68dc16f..3468892cf 100644 --- a/src/homeworks/ts1/1_base.test.js +++ b/src/homeworks/ts1/1_base.test.js @@ -1,26 +1,20 @@ -// Этот блок кода удалить и раскомментировать код ниже -it('remove it', () => { - expect(true).toBe(true); -}); +import { transformCustomers } from './1_base'; +describe('all', () => { + it('transformCustomers', () => { + const customers = [ + { id: 1, name: 'John', age: 25, isSubscribed: true }, + { id: 2, name: 'Mary', age: 40, isSubscribed: false }, + { id: 3, name: 'Bob', age: 32, isSubscribed: true }, + { id: 4, name: 'Alice', age: 22, isSubscribed: true }, + { id: 5, name: 'David', age: 48, isSubscribed: false }, + ]; -// import { transformCustomers } from './1_base'; -// -// describe('all', () => { -// it('transformCustomers', () => { -// const customers = [ -// { id: 1, name: 'John', age: 25, isSubscribed: true }, -// { id: 2, name: 'Mary', age: 40, isSubscribed: false }, -// { id: 3, name: 'Bob', age: 32, isSubscribed: true }, -// { id: 4, name: 'Alice', age: 22, isSubscribed: true }, -// { id: 5, name: 'David', age: 48, isSubscribed: false }, -// ]; -// -// expect(transformCustomers(customers)).toEqual({ -// 1: { name: 'John', age: 25, isSubscribed: true }, -// 2: { name: 'Mary', age: 40, isSubscribed: false }, -// 3: { name: 'Bob', age: 32, isSubscribed: true }, -// 4: { name: 'Alice', age: 22, isSubscribed: true }, -// 5: { name: 'David', age: 48, isSubscribed: false }, -// }); -// }); -// }); + expect(transformCustomers(customers)).toEqual({ + 1: { name: 'John', age: 25, isSubscribed: true }, + 2: { name: 'Mary', age: 40, isSubscribed: false }, + 3: { name: 'Bob', age: 32, isSubscribed: true }, + 4: { name: 'Alice', age: 22, isSubscribed: true }, + 5: { name: 'David', age: 48, isSubscribed: false }, + }); + }); +}); diff --git a/src/homeworks/ts1/1_base.ts b/src/homeworks/ts1/1_base.ts new file mode 100644 index 000000000..71c7fc681 --- /dev/null +++ b/src/homeworks/ts1/1_base.ts @@ -0,0 +1,85 @@ +/** + * Нужно превратить файл в ts и указать типы аргументов и типы возвращаемого значения + * */ +export const removePlus = (string: string): string => string.replace(/^\+/, ''); + +export const addPlus = (string: string): string => `+${string}`; + +export const removeFirstZeros = (value: string): string => value.replace(/^(-)?[0]+(-?\d+.*)$/, '$1$2'); + +export const getBeautifulNumber = (value: number, separator = ' '): string => + value?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator); + +export const round = (value: number, accuracy = 2): number => { + const d: number = 10 ** accuracy; + return Math.round(value * d) / d; +}; + +const transformRegexp = + /(matrix\(-?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, -?\d+(\.\d+)?, )(-?\d+(\.\d+)?), (-?\d+(\.\d+)?)\)/; + +export const getTransformFromCss = (transformCssString: string): { x: number; y: number } => { + const data = transformCssString.match(transformRegexp); + if (!data) return { x: 0, y: 0 }; + return { + x: parseInt(data[6], 10), + y: parseInt(data[8], 10), + }; +}; + +type RGBColor = [number, number, number]; +export const getColorContrastValue = ([red, green, blue]: RGBColor): number => + // http://www.w3.org/TR/AERT#color-contrast + Math.round((red * 299 + green * 587 + blue * 114) / 1000); + +export const getContrastType = (contrastValue: number): 'black' | 'white' => (contrastValue > 125 ? 'black' : 'white'); + +export const shortColorRegExp = /^#[0-9a-f]{3}$/i; +export const longColorRegExp = /^#[0-9a-f]{6}$/i; + +export const checkColor = (color: string): void | never => { + if (!longColorRegExp.test(color) && !shortColorRegExp.test(color)) throw new Error(`invalid hex color: ${color}`); +}; + +export const hex2rgb = (color: string): number[] => { + checkColor(color); + if (shortColorRegExp.test(color)) { + const red = parseInt(color.substring(1, 2), 16); + const green = parseInt(color.substring(2, 3), 16); + const blue = parseInt(color.substring(3, 4), 16); + return [red, green, blue]; + } + const red = parseInt(color.substring(1, 3), 16); + const green = parseInt(color.substring(3, 5), 16); + const blue = parseInt(color.substring(5, 8), 16); + return [red, green, blue]; +}; + +export const getNumberedArray = (arr: (string | number)[]) => arr.map((value, number) => ({ value, number })); + +type StringArray = { + value: T; + number: number; +}; +export const toStringArray = (arr: StringArray[]): string[] => arr.map(({ value, number }) => `${value}_${number}`); + +/** + * TypeScript Utility Types + * Record - Record - создает тип, который является записью с ключами, определенными в первом параметре, и значениями типа, определенного во втором параметре. + * Omit - выбирает свойства объекта типа T, исключая те, которые указаны в K + * + as - утверждение типов + * + * @param customers + */ +interface ICustomer { + id: number; + name: string; + age: number; + isSubscribed: boolean; +} +export const transformCustomers = (customers: ICustomer[]): Record> => { + return customers.reduce((acc, customer) => { + acc[customer.id] = { name: customer.name, age: customer.age, isSubscribed: customer.isSubscribed }; + return acc; + }, {} as Record>); +}; diff --git a/src/homeworks/ts1/2_repair.ts b/src/homeworks/ts1/2_repair.ts index 19e98c068..f93c55362 100644 --- a/src/homeworks/ts1/2_repair.ts +++ b/src/homeworks/ts1/2_repair.ts @@ -1,47 +1,42 @@ -/** - * Здесь код с ошибками типов. Нужно их устранить - * */ +export const getFakeApi = async (): Promise => { + const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json()); + console.log(result); +}; -// // Мы это не проходили, но по тексту ошибки можно понять, как это починить -// export const getFakeApi = async (): void => { -// const result = await fetch('https://jsonplaceholder.typicode.com/todos/1').then((response) => response.json()); -// console.log(result); -// }; -// -// // Мы это не проходили, но по тексту ошибки можно понять, как это починить -// export class SomeClass { -// constructor() { -// this.set = new Set([1]); -// this.channel = new BroadcastChannel('test-broadcast-channel'); -// } -// } -// -// export type Data = { -// type: 'Money' | 'Percent'; -// value: DataValue; -// }; -// -// export type DataValue = Money | Percent; -// -// export type Money = { -// currency: string; -// amount: number; -// }; -// -// export type Percent = { -// percent: number; -// }; -// -// // Здесь, возможно, нужно использовать as, возможно в switch передавать немного по-другому -// const getDataAmount = (data: Data): number => { -// switch (data.type) { -// case 'Money': -// return data.value.amount; -// -// default: { -// // eslint-disable-next-line @typescript-eslint/no-unused-vars -// const unhandled: never = data; // здесь, возможно, нужно использовать нечто другое. :never должен остаться -// throw new Error(`unknown type: ${data.type}`); -// } -// } -// }; +export class SomeClass { + set: Set; + channel: BroadcastChannel; + constructor() { + this.set = new Set([1]); + this.channel = new BroadcastChannel('test-broadcast-channel'); + } +} + +export type Data = { + type: 'Money' | 'Percent'; + value: DataValue; +}; + +export type DataValue = Money | Percent; + +export type Money = { + currency: string; + amount: number; +}; + +export type Percent = { + percent: number; +}; + +const getDataAmount = (data: Data): number => { + switch (data.type) { + case 'Money': + return (data.value as Money).amount; + + default: { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const unhandled: never = data as never; + throw new Error(`unknown type: ${data.type}`); + } + } +}; diff --git a/src/homeworks/ts1/3_write.test.js b/src/homeworks/ts1/3_write.test.js index 5b5173063..6b733bebe 100644 --- a/src/homeworks/ts1/3_write.test.js +++ b/src/homeworks/ts1/3_write.test.js @@ -1,35 +1,34 @@ -// Этот блок кода удалить и раскомментировать код ниже it('remove it', () => { expect(true).toBe(true); }); -// import { createRandomOperation, createRandomProduct } from './3_write'; -// -// describe('all', () => { -// it('operation', () => { -// const createdAt = '2023-06-06T12:06:56.957Z'; -// const operation = createRandomOperation(createdAt); -// expect(operation).toHaveProperty('createdAt', createdAt); -// expect(operation).toHaveProperty('id'); -// expect(operation).toHaveProperty('name'); -// expect(operation).toHaveProperty('desc'); -// expect(operation).toHaveProperty('createdAt'); -// expect(operation).toHaveProperty('amount'); -// expect(operation).toHaveProperty('category'); -// expect(operation).toHaveProperty('type'); -// }); -// -// it('product', () => { -// const createdAt = '2023-06-06T12:06:56.957Z'; -// const product = createRandomProduct(createdAt); -// expect(product).toHaveProperty('createdAt', createdAt); -// expect(product).toHaveProperty('id'); -// expect(product).toHaveProperty('name'); -// expect(product).toHaveProperty('photo'); -// expect(product).toHaveProperty('desc'); -// expect(product).toHaveProperty('createdAt'); -// expect(product).toHaveProperty('oldPrice'); -// expect(product).toHaveProperty('price'); -// expect(product).toHaveProperty('category'); -// }); -// }); +import { createRandomOperation, createRandomProduct } from './3_write'; + +describe('all', () => { + it('operation', () => { + const createdAt = '2023-06-06T12:06:56.957Z'; + const operation = createRandomOperation(createdAt); + expect(operation).toHaveProperty('createdAt', createdAt); + expect(operation).toHaveProperty('id'); + expect(operation).toHaveProperty('name'); + expect(operation).toHaveProperty('desc'); + expect(operation).toHaveProperty('createdAt'); + expect(operation).toHaveProperty('amount'); + expect(operation).toHaveProperty('category'); + expect(operation).toHaveProperty('type'); + }); + + it('product', () => { + const createdAt = '2023-06-06T12:06:56.957Z'; + const product = createRandomProduct(createdAt); + expect(product).toHaveProperty('createdAt', createdAt); + expect(product).toHaveProperty('id'); + expect(product).toHaveProperty('name'); + expect(product).toHaveProperty('photo'); + expect(product).toHaveProperty('desc'); + expect(product).toHaveProperty('createdAt'); + expect(product).toHaveProperty('oldPrice'); + expect(product).toHaveProperty('price'); + expect(product).toHaveProperty('category'); + }); +}); diff --git a/src/homeworks/ts1/3_write.ts b/src/homeworks/ts1/3_write.ts index 15f9dcdf2..444220af8 100644 --- a/src/homeworks/ts1/3_write.ts +++ b/src/homeworks/ts1/3_write.ts @@ -1,56 +1,110 @@ -/** - * Функции написанные здесь пригодятся на последующих уроках - * С помощью этих функций мы будем добавлять элементы в список для проверки динамической загрузки - * Поэтому в идеале чтобы функции возвращали случайные данные, но в то же время не абракадабру. - * В целом сделайте так, как вам будет удобно. - * */ - -/** - * Нужно создать тип Category, он будет использоваться ниже. - * Категория содержит - * - id (строка) - * - name (строка) - * - photo (строка, необязательно) - * - * Продукт (Product) содержит - * - id (строка) - * - name (строка) - * - photo (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - oldPrice (число, необязательно) - * - price (число) - * - category (Категория) - * - * Операция (Operation) может быть либо тратой (Cost), либо доходом (Profit) - * - * Трата (Cost) содержит - * - id (строка) - * - name (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - amount (число) - * - category (Категория) - * - type ('Cost') - * - * Доход (Profit) содержит - * - id (строка) - * - name (строка) - * - desc (строка, необязательно) - * - createdAt (строка) - * - amount (число) - * - category (Категория) - * - type ('Profit') - * */ - -/** - * Создает случайный продукт (Product). - * Принимает дату создания (строка) - * */ -// export const createRandomProduct = (createdAt: string) => {}; - -/** - * Создает случайную операцию (Operation). - * Принимает дату создания (строка) - * */ -// export const createRandomOperation = (createdAt: string) => {}; +type Category = { + id: string; + name: string; + photo?: string; +}; + +type Product = { + id: string; + name: string; + photo: string; + desc?: string; + createdAt: string; + oldPrice?: number; + price: number; + category: Category; +}; + +type Cost = { + id: string; + name: string; + desc?: string; + createdAt: string; + amount: number; + category: Category; + type: 'Cost'; +}; + +type Profit = { + id: string; + name: string; + desc?: string; + createdAt: string; + amount: number; + category: Category; + type: 'Profit'; +}; + +type Operation = Cost | Profit; + +const generateId = (): string => Math.random().toString(36).substring(2, 9); + +const getRandomInt = (min: number, max: number): number => Math.floor(Math.random() * (max - min + 1)) + min; + +const randomFromArray = (array: T[]): T => array[Math.floor(Math.random() * array.length)]; + +const categories: Category[] = [ + { id: 'cat1', name: 'Electronics', photo: 'electronics.jpg' }, + { id: 'cat2', name: 'Clothing', photo: 'clothing.jpg' }, + { id: 'cat3', name: 'Food', photo: 'food.jpg' }, + { id: 'cat4', name: 'Furniture' }, + { id: 'cat5', name: 'Books', photo: 'books.jpg' }, +]; + +const productNames: string[] = [ + 'Smartphone', + 'Laptop', + 'T-Shirt', + 'Jeans', + 'Apple', + 'Banana', + 'Chair', + 'Table', + 'Novel', + 'Textbook', +]; + +const operationNames: string[] = [ + 'Grocery shopping', + 'Salary', + 'Freelance work', + 'Restaurant bill', + 'Electricity bill', + 'Bonus', +]; + +export const createRandomProduct = (createdAt: string) => { + const category = randomFromArray(categories); + const name = randomFromArray(productNames); + const price = getRandomInt(10, 1000); + const oldPrice = Math.random() > 0.5 ? price + getRandomInt(5, 50) : undefined; + + return { + id: generateId(), + name, + photo: `${name.toLowerCase().replace(' ', '-')}.jpg`, + desc: Math.random() > 0.3 ? `Description for ${name}` : undefined, + createdAt, + oldPrice, + price, + category, + }; +}; + +export const createRandomOperation = (createdAt: string) => { + const isCost = Math.random() > 0.5; + const name = randomFromArray(operationNames); + const amount = getRandomInt(5, 500); + const category = randomFromArray(categories); + + const baseOperation = { + id: generateId(), + name, + desc: Math.random() > 0.3 ? `Description for ${name}` : undefined, + createdAt, + amount, + category, + }; + + return isCost ? { ...baseOperation, type: 'Cost' } : { ...baseOperation, type: 'Profit' }; +};