2024:写 TypeScript 必须改掉的 10 个坏习惯
大家好,我是CodeQi! 一位热衷于技术分享的码仔。
在过去的几年里,TypeScript 已经逐渐成为了前端开发的首选语言,尤其是那些追求更高代码质量和类型安全的开发者。不过,正如所有编程语言一样,随着时间的推移和技术的进步,我们的编程习惯也应该与时俱进。
👋 你有没有想过,自己在写 TypeScript 时是否养成了一些“坏习惯”?
随着 TypeScript 生态系统的进一步成熟,有些你以前觉得合理的做法,现在可能不太合理。接下来,我将分享10 个常见的 TypeScript 坏习惯,并告诉你如何改进它们,确保你的代码更健壮、性能更高、并且更加易于维护。
1. 不使用 strict 模式
当开发者为了减少“麻烦”而禁用 TypeScript 的 strict
模式时,往往是在给自己埋雷。💣
为什么不好?
strict
模式通过强制进行更严格的类型检查,帮助我们避免潜在的错误。如果你关掉它,TypeScript 就变得更像是 JavaScript,失去了静态类型带来的种种好处。短期内你可能会觉得更自由,但未来的重构和维护将变得更加棘手。
怎么改进?
在 tsconfig.json
中启用 strict
模式,这样你的代码在未来的迭代中会更加稳健:
{
"compilerOptions": {
"strict": true
}
}
2. 依赖 any 类型
any
可能是 TypeScript 中最具“争议”的类型之一,因为它违背了我们使用 TypeScript 的初衷:类型安全。
为什么不好?
any
让 TypeScript 失去意义。它让代码回归到“JavaScript 模式”,绕过了类型检查,最终可能导致各种运行时错误。
怎么改进?
使用 unknown
替代 any
,并在实际使用前对类型进行检查。unknown
更安全,因为它不会自动允许任何操作:
let data: unknown;
if (typeof data === "string") {
console.log(data.toUpperCase());
}
3. 过度使用类型断言
你是否经常用 as
关键字来“消除”编译错误?🙈 这种做法短期内看似有效,但可能会隐藏更多问题。
为什么不好?
类型断言会绕过 TypeScript 的安全机制,告诉编译器“别管了,我知道自己在做什么”。问题是,当你其实并不完全确定时,它会导致难以追踪的运行时错误。
怎么改进?
减少类型断言,使用类型保护函数代替:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
if (isString(data)) {
console.log(data.toUpperCase());
}
4. 忽视联合类型和交叉类型
联合类型 (|
) 和交叉类型 (&
) 是 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);
}
}
5. 使用非特定的返回类型
不为函数指定精确的返回类型,可能会让使用者摸不着头脑。🤔
为什么不好?
模糊的返回类型增加了代码的不确定性,调试难度也会增加。你失去了静态类型的优势,最终使代码变得不可靠。
怎么改进?
始终为函数指定明确的返回类型,哪怕它是一个联合类型:
function fetchData(): Promise<{ id: number; name: string }> {
return fetch("/data").then(response => response.json());
}
6. 忽视 null 和 undefined
一些开发者在处理 null
和 undefined
时掉以轻心,结果导致一堆潜在的运行时错误。
为什么不好?
JavaScript 允许变量为 null
或 undefined
,TypeScript 也有相应的工具帮助处理这些值。如果忽视它们,代码可能会在运行时崩溃。
怎么改进?
使用可选链 (?.
) 和空值合并操作符 (??
) 处理 null
和 undefined
:
const name = user?.profile?.name ?? "Guest";
7. 过度使用 Enums
在 TypeScript 中,Enums
有时会被滥用。尽管它们有其应用场景,但并不总是必要。
为什么不好?
Enums
会增加复杂性,尤其是在简单常量足够的情况下。
怎么改进?
考虑用 const
或字面量类型来替代枚举:
type Role = "Admin" | "User" | "Guest";
let userRole: Role = "Admin";
8. 不使用 readonly
如果不使用 readonly
来防止对象或数组的意外修改,代码中的副作用将难以控制。
为什么不好?
可变性会导致对象在不经意间被修改,造成难以调试的问题。
怎么改进?
尽可能使用 readonly
来确保不变性:
const data: readonly number[] = [1, 2, 3];
9. 忽视自定义类型保护
依赖隐式类型检查而非明确的类型保护,可能导致你错过一些重要的类型问题。
为什么不好?
没有自定义类型保护,你可能会在运行时错过一些类型错误,最终导致不可预期的行为。
怎么改进?
编写明确的类型保护函数:
function isUser(user: any): user is User {
return typeof user.email === "string";
}
10. 没有充分利用 unknown 类型
许多开发者默认使用 any
来处理未知类型,其实 unknown
是一个更好的选择。
为什么不好?
any
禁用了类型检查,而这正是使用 TypeScript 的初衷。unknown
则要求你在使用前对类型进行明确的验证。
怎么改进?
用 unknown
代替 any
,并在使用前进行类型缩小:
let input: unknown;
if (typeof input === "string") {
console.log(input.toUpperCase());
}
总结
2024 年,是时候告别这些坏习惯了!通过启用 strict
模式、避免使用 any
、掌握联合和交叉类型等高级特性,你的 TypeScript 代码将变得更强大、更灵活、更具维护性。希望这些建议能够帮助你在 TypeScript 之路上走得更远,写出更加优雅的代码!✨
来源:juejin.cn/post/7426298029286916146