Обработка ошибок в TypeScript
Обработка ошибок — важная часть обеспечения надёжности программы.
TypeScript предоставляет мощную систему типов, которая помогает разработчикам лучше обрабатывать и предотвращать ошибки.
В этой статье рассматриваются распространённые шаблоны обработки ошибок и лучшие практики в TypeScript.
Диаграмма SVG: Подходы к обработке ошибок
Зачем нужна хорошая обработка ошибок
Любая программа может столкнуться с ошибками, такими как сбои сетевых запросов, отсутствующие файлы, неверный пользовательский ввод и так далее.
Хорошая обработка ошибок может предотвратить сбои программы, предоставить понятные сообщения об ошибках и помочь разработчикам найти проблемы.
Система типов TypeScript может находить потенциальные проблемы во время компиляции, уменьшая количество ошибок времени выполнения.
Пояснение концепции:Существует два основных способа обработки ошибок: обработка исключений (try-catch) и обработка возвращаемых значений (тип Result). Первый выбрасывает исключения для указания ошибок, а второй передаёт информацию об ошибке через возвращаемые значения.
Пользовательские типы ошибок
Создавайте пользовательские типы ошибок путём расширения класса Error, что позволяет им нести больше информации об ошибке.
Это делает обработку ошибок более точной и структурированной.
Пример
// Расширить встроенный класс Error и добавить код ошибки
class AppError extends Error {
// Код ошибки для программной обработки ошибок
code: string;
// Конструктор
constructor(message: string, code: string) {
super(message); // Вызов конструктора родительского класса
this.name = "AppError"; // Установить имя ошибки
this.code = code; // Сохранить код ошибки
}
}
// Функция безопасного деления
function divide(a: number, b: number): number {
// Проверить, равен ли делитель нулю
if (b === 0) {
// Выбросить пользовательскую ошибку
throw new AppError("Нельзя делить на ноль", "DIVIDE_BY_ZERO");
}
return a / b;
}
// Использовать try-catch для перехвата ошибки
try {
var result = divide(10, 0);
} catch (error) {
// Проверить тип ошибки
if (error instanceof AppError) {
console.log("Ошибка приложения: " + error.message + ", код: " + error.code);
} else {
console.log("Неизвестная ошибка: " + error);
}
}
Вывод:
应用错误: Cannot divide by zero, 代码: DIVIDE_BY_ZERO
Код ошибки:Добавление кодов к ошибкам помогает программе точнее обрабатывать разные типы ошибок.
Тип Result для избежания исключений
Другой подход к обработке ошибок — использовать тип Result.
Он передаёт информацию об ошибке через возвращаемые значения вместо выбрасывания исключений. Этот подход распространён в функциональном программировании.
Пример
// При успехе содержит ok: true и значение; при ошибке содержит ok: false и ошибку
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
// Функция деления, использующая тип Result
function safeDivide(a: number, b: number): Result<number, string> {
// Проверить, равен ли делитель нулю
if (b === 0) {
// Вернуть результат с ошибкой
return { ok: false, error: "Нельзя делить на ноль" };
}
// Вернуть успешный результат
return { ok: true, value: a / b };
}
// Вызвать функцию и обработать результат
var result = safeDivide(10, 2);
// Обработать в зависимости от типа результата
if (result.ok) {
console.log("Результат: " + result.value);
} else {
console.log("Ошибка: " + result.error);
}
Вывод:
结果: 5
Преимущества:Тип Result делает обработку ошибок явной; вызывающие должны обрабатывать возможные ошибки и не могут игнорировать их.
Обработка ошибок в асинхронных функциях
В асинхронных функциях обработка ошибок особенно важна.
Вы можете использовать try-catch или тип Result для обработки ошибок в асинхронных операциях.
Пример
interface User {
id: number;
name: string;
}
// Имитация асинхронной функции для получения пользователя
async function fetchUser(id: number): Promise<Result<User, Error>> {
try {
// Имитация сетевого запроса
var response = await fetch("/api/users/" + id);
var user = await response.json();
// Вернуть успешный результат
return { ok: true, value: user };
} catch (error) {
// Вернуть результат с ошибкой
return { ok: false, error: error as Error };
}
}
// Главная функция
async function main() {
// Вызовите асинхронную функцию
var result = await fetchUser(1);
// Обработайте результат
if (result.ok) {
console.log("Пользователь: " + JSON.stringify(result.value));
} else {
console.log("Ошибка: " + result.error.message);
}
}
// Выполните главную функцию
main();
Вывод:
User: {"id":1,"name":"Alice"}
Совет:try-catch в асинхронной функции перехватывает любую ошибку, выброшенную await-выражениями.
Универсальная обёртка для обработки ошибок
Вы можете создать универсальную функцию обработки ошибок, чтобы упростить обработку ошибок в асинхронном коде.
Пример
// Принимает асинхронную функцию и возвращает тип Result
async function withErrorHandling<T>(
fn: () => Promise<T>
): Promise<Result<T, Error>> {
try {
// Выполнить переданную асинхронную функцию
var data = await fn();
// Вернуть успешный результат
return { ok: true, value: data };
} catch (error) {
// Вернуть результат с ошибкой
return { ok: false, error: error as Error };
}
}
// Использовать общую обработку ошибок
// Имитировать получение данных
var result = await withErrorHandling(async function() {
var response = await fetch("/api/data");
return response.json();
});
// Обработать на основе результата
if (result.ok) {
console.log("Данные: " + JSON.stringify(result.value));
} else {
console.error("Error:", result.error);
}
Лучшая практика:Обертывание общей логики обработки ошибок снижает дублирование кода и повышает удобство сопровождения кода.
Примечания
- Не игнорируйте ошибки:Не используйте пустые блоки catch для перехвата и игнорирования ошибок
- Четко указывайте типы ошибок:По возможности используйте конкретные типы ошибок вместо общего Error
- Границы ошибок:Создайте единый механизм обработки ошибок в приложении
- Не злоупотребляйте исключениями:Для предсказуемых ошибок предпочитайте возвращаемые значения выбрасыванию исключений
Совет:Выбирайте подход к обработке ошибок в зависимости от сценария: используйте исключения для ошибок программы, а Result — для бизнес-ошибок.
Итог
Хорошая обработка ошибок — основа для создания надежных приложений.
- Пользовательские ошибки:Расширьте класс Error и добавьте информацию, например коды ошибок
- Тип Result:Обрабатывайте ошибки через возвращаемые значения, избегая исключений
- async/await:Используйте try-catch для асинхронных ошибок
- Обертывание ошибок:Создавайте общие функции обработки ошибок
- Границы ошибок:Создайте единый механизм обработки ошибок
Лучшая практика:Выбирайте подходящий подход к обработке ошибок в зависимости от конкретного сценария, соблюдая баланс между читаемостью и надежностью кода.
Другие расширения