【早阅】改掉10个不好的TypeScript习惯

科技   2024-10-19 08:03   福建  

作者:@Safdar Ali
原文:https://dev.to/safdarali/10-bad-typescript-habits-to-break-in-2024-2p54

背景

TypeScript 作为一种在 JavaScript 基础上增加了静态类型系统的编程语言,近年来在开发者社区中越来越受欢迎。然而,随着 TypeScript 的不断发展,一些过去被认为是最佳实践的习惯可能已经变得过时或不再适用。Safdar Ali 在其文章《10 Bad TypeScript Habits To Break In 2024》中列举了十种常见的 TypeScript 不良习惯,并提供了改进建议。

【第3359期】没人告诉你的一件关于 TypeScript 的事

要点

文章指出了十种常见的 TypeScript 不良习惯,包括不使用严格模式、过度依赖 any 类型、滥用类型断言、忽视联合和交叉类型、使用非特定返回类型、忽略 null 和 undefined、过度使用枚举、不利用 readonly、忽视自定义类型守卫以及不充分利用 unknown 类型。

分析

一、 不使用严格模式 (strict Mode)

严格模式(strict mode)是 TypeScript 中的一项重要功能,它通过启用一系列更严格的类型检查来提高代码的健壮性。关闭严格模式会导致类型检查的松懈,增加代码出错的风险。

问题:许多开发者为了避免处理更严格的类型检查,会禁用 TypeScript 的严格模式。

弊端:关闭严格模式会降低 TypeScript 类型安全的有效性,可能导致意外错误,并增加未来重构的难度。

解决方案:在 tsconfig.json 文件中启用严格模式,强制执行更完善的类型检查,确保代码更加健壮。

 {
"compilerOptions": {
"strict": true
}
}
二、 过度依赖 any 类型

any 类型允许变量接受任何类型的值,这实际上绕过了 TypeScript 的类型检查机制。过度使用 any 类型会使 TypeScript 失去其静态类型系统的优势,增加运行时错误的可能性。

问题:开发者在不想思考正确类型时,经常使用 any 类型作为快速解决方案。

弊端:使用 any 类型会绕过 TypeScript 的所有类型检查,使其本质上又变回了 JavaScript。这可能导致运行时错误,因为 TypeScript 无法在开发过程中帮助捕捉错误。

解决方案:使用更具体的类型,例如 unknown,或者更好的是,为数据定义适当的类型。unknown 类型比 any 更安全,因为它强制在使用值之前进行类型检查。

 let data: unknown;
if (typeof data === "string") {
console.log(data.toUpperCase());
}
三、 随意使用类型断言

类型断言(type assertion)允许开发者强制 TypeScript 将一个值视为特定类型,即使该值可能不是该类型。滥用类型断言会导致代码的不安全性,因为 TypeScript 无法在编译时捕获这些潜在的错误。

问题:类型断言(as 关键字)可能会被过度使用,尤其是在开发者不确定类型并希望抑制 TypeScript 错误时。

弊端:类型断言可能导致不安全的代码,因为它们告诉 TypeScript 将值视为特定类型,即使它可能不是。如果值不是预期的类型,则可能导致运行时问题。

解决方案:限制类型断言的使用。可以使用类型守卫,它允许在使用值之前安全地检查和推断类型。

 function isString(value: unknown): value is string {
return typeof value === 'string';
}

if (isString(data)) {
console.log(data.toUpperCase());
}
四、 忽视联合类型和交叉类型

联合类型(union types)和交叉类型(intersection types)是 TypeScript 中强大的类型系统特性,能够更精确地描述复杂的数据结构。忽视这些类型会导致代码的冗长和类型定义的不精确。

问题:一些开发者即使在联合类型 (|) 和交叉类型 (&) 能使代码更具表现力和精确性的情况下,也避免使用它们。

弊端:不使用联合类型和交叉类型会导致代码过于冗长,并且可能会错过 TypeScript 以更简洁的方式描述複杂数据结构的能力。

解决方案:利用联合类型和交叉类型创建更灵活和可重用的类型定义。

 type Admin = {
isAdmin: true;
privileges: string[];
};

type User = {
isAdmin: false;
email: string;
};

type Person = Admin | User;
function logUser(person: Person) {
if (person.isAdmin) {
console.log(person.privileges);
} else {
console.log(person.email);
}
}
五、 使用非特定返回类型

函数返回类型的不明确会导致代码的可读性和可维护性下降。明确的返回类型有助于开发者更好地理解函数的预期输出,减少调试的难度。

问题:函数的返回类型通常是 any、object 或其他非特定类型,这使得函数的使用者需要自行弄清楚预期结果。

弊端:非特定返回类型会降低代码的可预测性,并增加调试难度。失去 TypeScript 静态类型检查的优势,使代码更容易出错。

解决方案:始终指定函数的确切返回类型。如果函数返回多种类型,请使用联合类型来描述它们。

 function fetchData(): Promise<{ id: number; name: string }> {
return fetch("/data").then((response) => response.json());
}
六、 忽略 null 和 undefined

JavaScript 中 null 和 undefined 的存在是常见的错误来源。TypeScript 提供了工具来处理这些值,忽视它们会导致运行时错误。

问题:一些开发者忽略代码中 null 和 undefined 值的存在,导致意外错误。

弊端:JavaScript 允许变量为 null 或 undefined,TypeScript 提供了显式处理这些值的工具。忽略它们可能导致在访问 null 或 undefined 的属性或调用方法时出现运行时错误。

解决方案:使用可选链操作符(?.)和空值合并运算符(??)安全地处理 null 和 undefined 值。

 const name = user?.profile?.name ?? "Guest";
七、 过度使用枚举

枚举(enum)在某些情况下可能过于复杂,尤其是对于简单的常量值。使用字面量类型或 const 对象可以更简洁地表达这些常量。

问题:枚举 (enum) 通常被过度用于简单的常量值,而其他类型(例如 const 或字面量联合类型)可能就足够了。

弊端:枚举会增加不必要的複杂性,尤其是在存在更简单的替代方案时。在某些情况下,它们甚至可能引入与可变性相关的问题。

解决方案:对于简单的常量值,请使用字面量类型或 const 对象。

 type Role = "Admin" | "User" | "Guest";

let userRole: Role = "Admin";
八、 不使用 readonly

readonly 关键字可以确保数据结构的不可变性,减少因意外修改数据而引发的错误。忽视 readonly 会导致代码的不可预测性增加。

问题:不使用 readonly 关键字会导致可变数据结构,这可能导致错误和意外的副作用。

弊端:可变性可能导致意外修改对象或数组,从而难以追踪错误。

解决方案:在适当的情况下使用 readonly 来强制不可变性。

 const data: readonly number[] = [1, 2, 3];
九、 忽视自定义类型守卫

自定义类型守卫(custom type guards)允许开发者明确地检查和推断类型,确保类型安全。忽视这些守卫会增加运行时错误的风险。

问题:许多开发者依赖隐式检查,而不是使用自定义类型守卫来确保类型安全。

弊端:如果没有显式类型守卫,则可能会在运行时遗漏某些类型,从而导致潜在错误。

解决方案:实现自定义类型守卫以显式检查类型,使代码更可靠。

 function isUser(user: any): user is User {
return typeof user.email === "string";
}
十、 不利用 unknown 类型

unknown 类型是 any 类型的一个更安全的替代品,它要求在使用值之前进行类型检查。不使用 unknown 类型会导致类型检查的缺失。

问题:开发者通常在最初不知道类型时,默认使用 any 作为变量的类型。

弊端:any 禁用了类型检查,这违背了使用 TypeScript 的目的。

解决方案:在最初不确定类型时,请使用 unknown 类型作为变量的类型,并根据需要缩小类型。

 let input: unknown;
if (typeof input === "string") {
console.log(input.toUpperCase());
}

影响

这些不良习惯的存在会显著影响代码的质量和可维护性。通过打破这些习惯,开发者可以编写更健壮、更高效的 TypeScript 代码,减少错误的发生,并提高代码的可读性和可维护性。此外,随着 TypeScript 的不断发展,采用最新的最佳实践将有助于开发者保持技术的领先地位。

结论

Safdar Ali 的文章为 TypeScript 开发者提供了一份宝贵的指南,帮助他们识别并改进不良的编程习惯。通过遵循这些建议,开发者可以显著提升他们的代码质量,减少错误,并更好地利用 TypeScript 的强大功能。未来,随着 TypeScript 的进一步发展,保持对最佳实践的关注将变得尤为重要。

AI 阅:了解技术资讯的一种方式。


前端早读课
探索前端技术,体验产品的情感, 项目思考的指引,塑造独立开发者的未来。
 最新文章