TypeScript 规范项目错误处理

简介: 笔记

5.png

在 JavaScript 开发中,通常都不太重视起错误处理,捕获和记录错误对于任何项目的开发周期都是至关重要的。随着 TypeScript 项目开发多了,开始意识到并不真正了解错误处理。经常在项目代码中看到一下类似代码:

try {
    throw new Error("Oops")
} catch (error) {
    console.error(error.message)
}

errorunknown 类型 ,因此在将其转换为新类型或缩小类型范围之前,不能对 error 执行任何操作。正确的处理方式是缩小类型,将看看如何做到这一点,但为什么这是必要的?

在 JavaScript 中,几乎任何东西都可以被抛出:


throw "oops"
throw 210
throw null
throw { message: "异常错误" }

所以真正被捕获的错误是未知的。但是,可以通过使用 TypeScript 的多种方式干净地处理错误。


JavaScript错误的基础知识


JavaScript 中的错误类型,在 JavaScript 中有许多类型的错误,但最常见的是:

  • ReferenceError:代码引用了一个不存在的变量。
  • TypeError:值不是预期的错误类型
  • SyntaxError:代码在语法上无效

抛出错误

有时需要手动抛出错误,例如,可能有一些代码依赖于函数调用的返回值,但有可能该值是 undefined,或者至少在 TypeScript 认为是 undefined。在下面这个例子中,抛出是缩小返回用户范围的最佳解决方案。


// 通常方式
function createProject() {
    const user = getUser();
    saveProject({ name: "", userId: user.id })
}
// 避免异常
function createProject() {
    const user = getUser();
    if (!user) {
        return;
    }
    saveProject({ name: "", userId: user.id })
}
// 最佳方式,抛出异常
function createProject() {
    const user = getUser();
    if (!user) {
        throw new ReferenceError('用户不存在')
    }
    saveProject({ name: "", userId: user.id })
}

捕获错误

一旦错误被抛出,它将在调用堆栈中冒泡,直到被 try/catch 语句捕获。当在 try 块内运行的代码抛出错误时,它将在 catch 块中被捕获,错误可能源自嵌套在函数内部的函数,并且会冒泡直到被捕获。

try {
    throw new ReferenceError();
} catch (error) {
    console.error(error)
}

缩小错误类型

一旦被捕获,检查所抛出的错误类型可能很有用。这使能够将类型从未知缩小到可以与之交互的特定类型(可以直观的理解错误),可以用 instanceof 做到这一点:


try {
    throw new ReferenceError();
} catch (error) {
    if (error instanceof ReferenceError) {
        console.error(error.message)
    }
}

设计模式


设计模式是软件设计中常见问题的解决方案,这些模式很容易重复使用并且富有表现力。在最新的项目中,将代码按域分组在名为 Features 的目录中,它可以包含相关的组件、钩子、类型、错误等等,每个 Feature 目录都包含一个 errors.ts 文件,在其中为各自的域定义了一个自定义错误类。

创建自定义错误类型

errors.ts 文件中,导出了一个 class。为潜在名称维护一个联合类型,这增加了一些不错的智能感知和类型安全。该类扩展了 Error 对象,它允许插入堆栈跟踪(对于大多数 JS 运行时)。


type ErrorName =
    'GET_PROJECT_ERROR' | 'CREATE_PROJECT_ERROR' | 'PROJECT_LIMIT_REACHED';
export class ProjectError extends Error {
    name: ErrorName;
    message: string;
    cause: any;
    constructor({ name, message, cause }: {
        name: ErrorName;
        message: string;
        cause?: any;
    }) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause;
    }
}

抛出自定义错误

实例化新错误时,name 值具有智能感知,并且必须是联合类型中定义的名称之一。

export async function createProject() {
    const { data, error } = await api.createProject();
    if (error) {
        throw new ProjectError({
            name: "CREATE_PROJECT_ERROR",
            message: "API error occurred while creating project",
            cause: error
        })
    }
    if (data.length === projectLimit) {
        throw new ProjectError({
            name: "PROJECT_LIMIT_REACHED",
            message: "Project limit has been reached."
        })
    }
    return data;
}

捕获自定义错误

当错误被捕获时,可以使用 instanceof 缩小错误类型。一旦缩小范围,error.name 就会智能感知,此时可以根据抛出的错误名称执行逻辑。在此示例中,PROJECT_LIMIT_REACHED 错误是要向用户显示的错误,提供了一条专门为用户呈现的消息。

try {
    await createProject();
} catch (error) {
    if (error instanceof ProjectError) {
        if (error.name === "PROJECT_LIMIT_REACHED") {
            toast(error.message)
        }
    }
}

定义可重用的错误库

由于项目中有很多 errors.ts 文件,类中唯一的动态代码是名称的联合类型,因此可以对代码进行优化,创建了一个 ErrorBase 类,它接受用作名称类型的泛型。

export class ErrorBase<T extends string> extends Error {
    name: T;
    message: string;
    cause: any;
    constructor({ name, message, cause }: { name: T, message: string, cause?: any }) {
        super();
        this.name = name;
        this.message = message;
        this.cause = cause
    }
}

现在,当创建一个新的自定义错误类时,可以扩展这个基类,需要做的就是给它提供可用名称的联合类型。

import { ErrorBase } from "./error-base"
type ErrorName =
    'GET_PROJECT_ERROR' | 'CREATE_PROJECT_ERROR' | 'PROJECT_LIMIT_REACHED';
export class TeamError extends ErrorBase<ErrorName>{ }

总结


设计模式让代码变得更容易维护,处理错误只是维护良好的应用程序的一部分,另一个重要步骤是使用类似 Sentry 的工具记录跟踪错误。


相关文章
|
7月前
|
前端开发 JavaScript 测试技术
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
199 0
|
2月前
|
设计模式 监控 JavaScript
TypeScript 在大型项目内网管理监控软件中的结构优化
本文探讨了 TypeScript 在大型项目内网管理监控软件中的结构优化,包括模块划分与组织、接口与抽象类的使用以及依赖注入与控制反转的设计模式,通过具体代码示例展示了这些技术的应用,提高了代码的可读性、可维护性和灵活性。
44 3
|
25天前
|
JavaScript 前端开发 安全
JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择
本文深入探讨了JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择。JavaScript以其灵活性和广泛的生态支持著称,而TypeScript通过引入静态类型系统,提高了代码的可靠性和可维护性,特别适合大型项目。文章还讨论了结合使用两种语言的优势,以及如何根据项目需求和技术背景做出最佳选择。
44 4
|
1月前
|
前端开发 JavaScript
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
|
2月前
|
JavaScript 前端开发 测试技术
JavaScript与TypeScript:为何TypeScript成为大型项目的首选
JavaScript与TypeScript:为何TypeScript成为大型项目的首选
32 1
|
5月前
|
JavaScript 前端开发 开发工具
TypeScript的介绍,let age:number = xxx,可以直接看出数据类型,Type由微软开发,可以在任何浏览器和系统中运行,比较适合大型项目,TypeScript的安装
TypeScript的介绍,let age:number = xxx,可以直接看出数据类型,Type由微软开发,可以在任何浏览器和系统中运行,比较适合大型项目,TypeScript的安装
|
4月前
|
JavaScript 前端开发 测试技术
TypeScript逆袭!大型项目为何对它情有独钟?揭秘背后的真相!
【8月更文挑战第27天】随着前端领域的快速发展,JavaScript已成为Web开发的核心语言。然而,在处理大型项目时,其弱类型特性导致的维护困难和易错性等问题日益突出。为解决这些问题,TypeScript应运而生,逐渐成为大型项目的首选方案。
48 3
|
5月前
|
JavaScript 前端开发 IDE
React 项目中有效地使用 TypeScript
React 项目中有效地使用 TypeScript
|
4月前
|
JavaScript 前端开发 安全
TypeScript在项目中应用
【8月更文挑战第4天】TypeScript在项目中应用
44 0
|
6月前
|
监控 JavaScript 前端开发
如何在现有的 JavaScript 项目中渐进式地采用 TypeScript
【6月更文挑战第13天】TypeScript,JavaScript的超集,引入静态类型和更多特性,提升代码安全性和可读性。在JavaScript项目中渐进式采用TypeScript可从新模块开始,逐步转换代码,编写.d.ts文件支持第三方库,配置编译选项,并编写测试用例。通过监控和评估,改善项目质量和效率。大型项目尤其受益于TypeScript的类型安全、社区支持和工具兼容性。
79 3
下一篇
DataWorks