Я хорошо отдохнул на майских — и, честно говоря, мне это понравилось)
Посты могут выходить чуть реже, но качество контента не меняется. Хуже точно не станет🙃
Посты могут выходить чуть реже, но качество контента не меняется. Хуже точно не станет
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11 5
Сегодня немного затронем работу с ошибками в 🖼️
Создание ошибок
Чтобы создать ошибку, нужно создать новый экземпляр класса
Мы создаём объект ошибки с сообщением и выбрасываем с помощью
Свойства
Каждый объект ошибки имеет несколько стандартных свойств:
-
-
-
Обработка ошибок
Использование
Ошибки не всегда должны прерывать выполнение приложения. С помощью
#JavaScript
Создание ошибок
Чтобы создать ошибку, нужно создать новый экземпляр класса
Error и передать сообщение в конструктор:
try {
throw new Error("Что-то пошло не так!");
} catch (error) {
console.error(error.message); // Что-то пошло не так!
}
Мы создаём объект ошибки с сообщением и выбрасываем с помощью
throw. Ошибка перехватывается в блоке catch, где мы можем вывести её сообщение.Свойства
Каждый объект ошибки имеет несколько стандартных свойств:
-
message — сообщение об ошибке.-
name — тип ошибки, по умолчанию это Error.-
stack — стек вызовов, который позволяет увидеть, откуда была вызвана ошибка.Обработка ошибок
Использование
throw и try...catch помогает контролировать ошибки в коде и избежать краша нашего приложения. Например, можно перехватить её и выполнить другие действия:
try {
const result = someFunction(); // Эта функция выбросит ошибку
} catch (error) {
console.error("Произошла ошибка:", error.message);
// Тут можно выполнить альтернативные действия
}
Ошибки не всегда должны прерывать выполнение приложения. С помощью
try...catch можно контролировать, как ошибки влияют на дальнейшие действия.#JavaScript
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍4👾2
Хотел бы обсудить сохранение постов.
Многие из нас сохраняют интересные посты. Но возвращаемся ли мы к этим сохранёнкам? Чаще всего — нет.
Почему так?
Потому что сохранение — это не запоминание. Это как положить книгу на полку и подумать, что ты уже её прочитал.
И главное мы почти никогда не возвращаемся к сохраненкам) Просто накапливаем.
А как лучше?
1. Если просто интересно — лучше прочитай сейчас, чем потом. Потом не наступит✅
2. Если хочешь попробовать — сразу пробуй🍺
3. Сохраняй меньше, но осознаннее🧠
4. Не сохраняй вообще, а читай и забывай — это тоже нормально✍️
Сохрани этот пост чтобы не потерять🚨
Ставь палец вверх если сохранил 👍
#BestPractices #Obsidian
Многие из нас сохраняют интересные посты. Но возвращаемся ли мы к этим сохранёнкам? Чаще всего — нет.
Почему так?
Потому что сохранение — это не запоминание. Это как положить книгу на полку и подумать, что ты уже её прочитал.
И главное мы почти никогда не возвращаемся к сохраненкам) Просто накапливаем.
А как лучше?
1. Если просто интересно — лучше прочитай сейчас, чем потом. Потом не наступит
2. Если хочешь попробовать — сразу пробуй
3. Сохраняй меньше, но осознаннее
4. Не сохраняй вообще, а читай и забывай — это тоже нормально
Сохрани этот пост чтобы не потерять
Ставь палец вверх если сохранил 👍
#BestPractices #Obsidian
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13😁7🔥3🤯1
Привет! Хотя регулярность постов и изменилась, неделя по-прежнему начинается с разбора задач с собеседований)
У нас есть пример типизированого массива:
И дана функция поиска по массиву, которую нужно типизировать:
Пример использования этой функции с массивом:
Задача:
Типизировать функцию
Решение:
1.
-
-
2. Параметры функции:
-
-
-
Вот и все) Мы типизировали функцию с помощью дженериков и сделали её универсальной для любых подобных массивов. Теперь мы можем гарантировать, что функция будет принимать только валидные аргументы.
В этом примере я не указал явно тип возвращаемого значения, так как TypeScript подтянет его автоматически. Но если функция будет меняться, лучше явно прописывать возвращаемый тип, чтобы избежать случайных ошибок в будущем.
#JavaScript #interview #typescript
У нас есть пример типизированого массива:
interface Student {
name: string;
age: number;
hasScar: boolean;
}
const students: Student[] = [
{ name: "Harry", age: 17, hasScar: true },
{ name: "Ron", age: 17, hasScar: false },
{ name: "Hermione", age: 16, hasScar: false },
];
И дана функция поиска по массиву, которую нужно типизировать:
function getBy(arr, prop, value) {
return arr.find(item => item[prop] === value) || null;
}
Пример использования этой функции с массивом:
const result = getBy(students, "name", "Hermione");
console.log(result);
Задача:
Типизировать функцию
getBy. Решение:
function getBy<T, K extends keyof T>(arr: T[], prop: K, value: T[K]) {
return arr.find(item => item[prop] === value) || null;
}
1.
<T, K extends keyof T> — дженерик:-
T — это универсальный тип, который представляет тип объекта внутри массива arr.-
K extends keyof T — означает, что K — это ключ объекта T. Тип keyof T — это объединение всех ключей объекта T. 2. Параметры функции:
-
arr: T[] — массив объектов типа T.-
prop: K — ключ, по которому будем искать совпадение.-
value: T[K] — значение, с которым будем сравнивать. Тип значения автоматически подтягивается из типа свойства prop. Вот и все) Мы типизировали функцию с помощью дженериков и сделали её универсальной для любых подобных массивов. Теперь мы можем гарантировать, что функция будет принимать только валидные аргументы.
В этом примере я не указал явно тип возвращаемого значения, так как TypeScript подтянет его автоматически. Но если функция будет меняться, лучше явно прописывать возвращаемый тип, чтобы избежать случайных ошибок в будущем.
#JavaScript #interview #typescript
👍8🔥4🤯4
В TypeScript 🖼️ есть два основных способа описания структуры данных — интерфейсы и типы. Когда и что выбирать?
Интерфейсы в TypeScript обычно используются для описания структуры объектов, особенно если они предполагают возможность расширения.
Их можно расширять с помощью
Типы идеально подходят для создания объединений и пересечений типов. Они пригодяся, когда нужно описать переменную, которая может быть одним из нескольких типов.
Пример объединения:
Пример пересечения:
Типы позволяют создавать псевдонимы для различных структур данных.
Что использовать?
Интерфейсы лучше использовать, когда:
— Нужно описать структуру объекта, которая может быть расширена.
— Работаете с объектами или классами, которые предполагают расширяемость.
Типы подходят, когда:
— Необходимо создать сложные структуры данных с объединениями или пересечениями.
— Нужно создавать псевдонимы для существующих типов или описывать более сложные типы данных.
#typescript #BestPractices
Интерфейсы в TypeScript обычно используются для описания структуры объектов, особенно если они предполагают возможность расширения.
Их можно расширять с помощью
extends, который позволяет создавать новые структуры на основе существующих.
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
const dog: Dog = {
name: 'Кнопка',
breed: 'Лабрадор'
};
Типы идеально подходят для создания объединений и пересечений типов. Они пригодяся, когда нужно описать переменную, которая может быть одним из нескольких типов.
Пример объединения:
type Result = 'success' | 'error';
const result: Result = 'success'; // Ок
const error: Result = 'failure'; // Будет ошибка
Пример пересечения:
type Person = { name: string };
type Worker = { job: string };
type Employee = Person & Worker;
const employee: Employee = {
name: 'Иван',
job: 'Frontender'
};
Типы позволяют создавать псевдонимы для различных структур данных.
type Coordinates = [number, number];
const point: Coordinates = [10, 20];
Что использовать?
Интерфейсы лучше использовать, когда:
— Нужно описать структуру объекта, которая может быть расширена.
— Работаете с объектами или классами, которые предполагают расширяемость.
Типы подходят, когда:
— Необходимо создать сложные структуры данных с объединениями или пересечениями.
— Нужно создавать псевдонимы для существующих типов или описывать более сложные типы данных.
#typescript #BestPractices
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍5👏2
Когда мы пишем приложения, важно обеспечить их стабильность, расширяемость и простоту поддержки. В этом посте узнаем про принципы SOLID, которые помогают с этим)
Используя SOLID-принципы, вы пишете код, который легче тестировать, поддерживать и развивать.
SOLID — это аббревиатура, которая объединяет 5 принципов:
S - Single Responsibility Principle (Принцип единой ответственности)
Каждый класс или компонент должен отвечать только за одну задачу. Это упрощает тестирование и отладку, потому что если что-то идет не так, вы точно знаете, какой класс или компонент за это отвечает. Такой подход также облегчает расширение приложения, так как изменение в одном месте не затронет другие части.
O - Open/Closed Principle (Принцип открытости/закрытости)
Классы должны быть открыты для расширения, но закрыты для модификации. Это означает, что вы можете добавлять новый функционал, не изменяя существующий код. Это достигается через использование абстракций, таких как интерфейсы и наследование.
L - Liskov Substitution Principle (Принцип подстановки Лисков)
Объекты базового класса должны быть заменяемыми объектами производного класса без нарушения корректности программы. Другими словами, наследуемые классы должны вести себя как их базовые классы, чтобы не ломать логику приложения.
I - Interface Segregation Principle (Принцип разделения интерфейсов)
Не стоит создавать универсальные интерфейсы, которые будут иметь множество методов, не используемых в разных классах. Лучше создавать несколько более специализированных интерфейсов. Это уменьшает зависимость классов и облегчает поддержку кода.
D - Dependency Inversion Principle (Принцип инверсии зависимостей)
Высокоуровневые модули не должны зависеть от низкоуровневых, а обе эти категории должны зависеть от абстракций. Это позволяет сделать код гибким и менее зависимым от конкретных реализаций.
Применение этих принципов поможет писать более чистый и поддерживаемый код, который будет легко расширяться и адаптироваться под изменения.
#BestPractices
Используя SOLID-принципы, вы пишете код, который легче тестировать, поддерживать и развивать.
SOLID — это аббревиатура, которая объединяет 5 принципов:
S - Single Responsibility Principle (Принцип единой ответственности)
Каждый класс или компонент должен отвечать только за одну задачу. Это упрощает тестирование и отладку, потому что если что-то идет не так, вы точно знаете, какой класс или компонент за это отвечает. Такой подход также облегчает расширение приложения, так как изменение в одном месте не затронет другие части.
O - Open/Closed Principle (Принцип открытости/закрытости)
Классы должны быть открыты для расширения, но закрыты для модификации. Это означает, что вы можете добавлять новый функционал, не изменяя существующий код. Это достигается через использование абстракций, таких как интерфейсы и наследование.
L - Liskov Substitution Principle (Принцип подстановки Лисков)
Объекты базового класса должны быть заменяемыми объектами производного класса без нарушения корректности программы. Другими словами, наследуемые классы должны вести себя как их базовые классы, чтобы не ломать логику приложения.
I - Interface Segregation Principle (Принцип разделения интерфейсов)
Не стоит создавать универсальные интерфейсы, которые будут иметь множество методов, не используемых в разных классах. Лучше создавать несколько более специализированных интерфейсов. Это уменьшает зависимость классов и облегчает поддержку кода.
D - Dependency Inversion Principle (Принцип инверсии зависимостей)
Высокоуровневые модули не должны зависеть от низкоуровневых, а обе эти категории должны зависеть от абстракций. Это позволяет сделать код гибким и менее зависимым от конкретных реализаций.
Применение этих принципов поможет писать более чистый и поддерживаемый код, который будет легко расширяться и адаптироваться под изменения.
#BestPractices
🔥15👍3
Please open Telegram to view this post
VIEW IN TELEGRAM
❤15 5
Всем привет!
Начнем эту неделю с мемов и настроимся на продуктивную рабочую неделю🖥
А я начну неделю с дейоффа😀
Начнем эту неделю с мемов и настроимся на продуктивную рабочую неделю
А я начну неделю с дейоффа
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
😁12🔥3
Сегодня у нас очередная задача с собеседования, связанная с рекурсией)
Задача:
Нужно распарсить вложенный объект, чтобы получить значение самого глубокого уровня.
Пример вызова функции:
Решение:
1.
2. Берём первое значение —
3. Если это значение — не объект, возвращаем его.
4. Если это объект, вызываем
Для кого-то эта задача может показаться совсем простой, но на практике некоторые мидлы задумываются над ней.
#interview #JavaScript
Задача:
Нужно распарсить вложенный объект, чтобы получить значение самого глубокого уровня.
Пример вызова функции:
const obj = { red: { fast: { fancy: { car: "lamba" } } } };
console.log(objParse(obj)); // "lamba"
Решение:
function objParse(obj) {
const [value] = Object.values(obj); // 1, 2
if (typeof value !== "object") { // 3
return value;
}
return objParse(value); // 4
}
1.
Object.values(obj) возвращает массив всех значений объекта. 2. Берём первое значение —
value.3. Если это значение — не объект, возвращаем его.
4. Если это объект, вызываем
objParse рекурсивно.Для кого-то эта задача может показаться совсем простой, но на практике некоторые мидлы задумываются над ней.
#interview #JavaScript
🔥9👍4
Работа с API, кэширование, обновление данных и обработка ошибок — всё это неизбежно возникает в любом приложении. На выбор у нас есть много подходов и инструментов. Один из таких — React Query.
Что такое React Query?
Это библиотека для управления данными в React-приложениях. Она помогает работать с запросами и решает типичные задачи, связанные с их загрузкой, кэшированием, обновлением и обработкой ошибок.
Какие проблемы решает?
1. Вместо написания шаблонного кода для запросов, состояний и обработки ошибок — можно использовать готовые хуки.
2. Данные автоматически кэшируются, и повторные запросы выполняются только при необходимости.
3. Готовые состояния и возможность легко повторить запрос.
4. Минимизирует количество запросов к API за счет кэширования и умной стратегии обновления.
5. Реализация сложных сценариев становится проще.
Как использовать React Query?
1. Установите библиотеку в проект:
2.Оберните приложение в
3. Используйте хуки:
Преимущества React Query
- Автоматическое кэширование и минимизация запросов.
- Простая обработка ошибок и состояний.
- Гибкость и удобство настройки под любые задачи.
Когда использовать React Query?
- Если проект работает с API.
- Если нужно кэшировать данные и минимизировать количество запросов.
#react #api
Что такое React Query?
Это библиотека для управления данными в React-приложениях. Она помогает работать с запросами и решает типичные задачи, связанные с их загрузкой, кэшированием, обновлением и обработкой ошибок.
Какие проблемы решает?
1. Вместо написания шаблонного кода для запросов, состояний и обработки ошибок — можно использовать готовые хуки.
2. Данные автоматически кэшируются, и повторные запросы выполняются только при необходимости.
3. Готовые состояния и возможность легко повторить запрос.
4. Минимизирует количество запросов к API за счет кэширования и умной стратегии обновления.
5. Реализация сложных сценариев становится проще.
Как использовать React Query?
1. Установите библиотеку в проект:
npm install @tanstack/react-query
2.Оберните приложение в
QueryClientProvider:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Component />
</QueryClientProvider>
);
}
3. Используйте хуки:
useQuery для загрузки данных:
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
});
useMutation для изменения данных:
const { mutate } = useMutation({
mutationFn: updateTodo,
});
mutate({ id: 1, text: 'Updated Todo' });
Преимущества React Query
- Автоматическое кэширование и минимизация запросов.
- Простая обработка ошибок и состояний.
- Гибкость и удобство настройки под любые задачи.
Когда использовать React Query?
- Если проект работает с API.
- Если нужно кэшировать данные и минимизировать количество запросов.
#react #api
👏7👍3🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Вы наверняка видели OTP-поля для ввода кодов. А знаете, как они делаются?
Сегодня разберёмся, как они делаются с помощью атрибута
Что делает атрибут size?
Атрибут
Поле будет визуально рассчитано примерно на 6 символов.
Пример
Один из частых кейсов — OTP-поля. Мы хотим, чтобы каждое поле занимало ровно одно место:
1. Атрибут
2.
Демо: CodePen
Ограничения и фишки:
1. Работает с типами:
2. Не ограничивает ввод — для этого есть
3. CSS
#HTML #CSS #BestPractices
Сегодня разберёмся, как они делаются с помощью атрибута
size.Что делает атрибут size?
Атрибут
size указывает примерное количество видимых символов в поле ввода. Это влияет только на ширину, но не ограничивает количество вводимых символов.
<input type="text" size="6">
Поле будет визуально рассчитано примерно на 6 символов.
Пример
Один из частых кейсов — OTP-поля. Мы хотим, чтобы каждое поле занимало ровно одно место:
<input type="text" size="1" maxlength="1">
<input type="text" size="1" maxlength="1">
<input type="text" size="1" maxlength="1">
<input type="text" size="1" maxlength="1">
1. Атрибут
size="1" делает поле под один символ. 2.
maxlength="1" ограничивает ввод до одного символа.Демо: CodePen
Ограничения и фишки:
1. Работает с типами:
text, search, tel, url, email, password2. Не ограничивает ввод — для этого есть
maxlength3. CSS
width перекроет size, если задать оба#HTML #CSS #BestPractices
👍9❤2
Использовали атрибут inert?
Этот атрибут позволяет отключить часть интерфейса от взаимодействия — элементы становятся недоступными для клика, фокуса и скринридеров.
Что делает inert?
Атрибут удаляет элемент из порядка навигации — кликнуть, сфокусироваться или ввести данные внутри него нельзя.
Поведение похоже на
—
— В отличие от
💻 Пример использования:
Стилизация элементов🖼️
Делаем элементы чуть прозрачными, чтобы показать, что они неактивны.
Добавляем через JS🖼️
Когда использовать?
1. Модальные окна — чтобы отключить остальной интерфейс при открытой модалке
2. Загрузка данных — временно блокировать зону, пока грузятся данные
3. Сложные формы — делать часть формы неактивной до выполнения условий
Поддержка браузерами: CanIUse
#HTML #accessibility
Этот атрибут позволяет отключить часть интерфейса от взаимодействия — элементы становятся недоступными для клика, фокуса и скринридеров.
Что делает inert?
Атрибут удаляет элемент из порядка навигации — кликнуть, сфокусироваться или ввести данные внутри него нельзя.
Поведение похоже на
disabled, но есть важные отличия:—
inert можно применить к любым элементам— В отличие от
disabled, текст внутри inert нельзя выделить, и он не реагирует на кастомные эффекты наведения или фокуса
<main inert>
<!-- Здесь всё будет неактивно -->
</main>
Стилизация элементов
inert не влияет на стили по умолчанию — нужно самостоятельно делать элементы визуально неактивными, например:
[inert] {
opacity 0.7;
}
Делаем элементы чуть прозрачными, чтобы показать, что они неактивны.
Добавляем через JS
const element = document.body;
// Добавляем inert
element.inert = true;
// Удаляем inert
element.inert = false;
Когда использовать?
1. Модальные окна — чтобы отключить остальной интерфейс при открытой модалке
2. Загрузка данных — временно блокировать зону, пока грузятся данные
3. Сложные формы — делать часть формы неактивной до выполнения условий
Поддержка браузерами: CanIUse
#HTML #accessibility
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍3👏1
Недавно мы разбирали(тык) работу с ошибками в JS.
Сегодня рассмотрим создание кастомных ошибок. Они позволяют точнее описывать, что именно пошло не так, и обрабатывать ошибки более точечно.
Вместо обычного
Что происходит?
1. Мы наследуемся от встроенного
2. Функция
3. В блоке
4. В блоке
Зачем это нужно?
1. Проще различать типы ошибок
2. Можно точечно обрабатывать нужные ошибки с помощью
3. Можно сделать более детальные ошибки.
#JavaScript #BestPractices
Сегодня рассмотрим создание кастомных ошибок. Они позволяют точнее описывать, что именно пошло не так, и обрабатывать ошибки более точечно.
Вместо обычного
Error можно создать свой класс, унаследованный от него:
class ValidationError extends Error { // 1
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
function validateUser(user) { // 2
if (!user.name) {
throw new ValidationError("Поле 'name' обязательно");
}
}
try {
validateUser({}); // 3
} catch (error) {
if (error instanceof ValidationError) { // 4
console.error("Ошибка валидации:", error.message);
} else {
throw error;
}
}
Что происходит?
1. Мы наследуемся от встроенного
Error, чтобы определить новый тип ошибки — ValidationError.2. Функция
validateUser проверяет, есть ли у объекта поле name. Если его нет — выбрасывает кастомную ошибку ValidationError с понятным сообщением.3. В блоке
try вызываем validateUser, передавая объект без name.4. В блоке
catch ловим ошибку и проверяем, является ли она экземпляром ValidationError с помощью instanceof.Зачем это нужно?
1. Проще различать типы ошибок
2. Можно точечно обрабатывать нужные ошибки с помощью
instanceof.3. Можно сделать более детальные ошибки.
#JavaScript #BestPractices
👍11🔥3👏1