写 TypeScript 必须改掉的16个坏习惯!!!

前言

TypeScript 在前端项目中已经是标配,使用 TypeScript 有很多好处,它让 JavaScript 拥有了强大的类型系统。

由于 JavaScript 本身是弱类型,很多前端开发人员并没有类型概念,对类型系统理解不深,常常走了不少弯路。本文总结了 16 个最常见的坑,结合实际例子帮助你少踩坑、写出更安全、更可维护的代码。

滥用 any

有些小伙伴在做 TS 项目时,为了避免写类型,直接使用anyany 会关闭类型检查,相当于"告诉 TypeScript 别管我了"。这会让整个类型系统形同虚设。

错误示例:

typescript 复制代码
function parseData(data: any) {
  return data.user.name.toUpperCase();
}

parseData(null); // 运行时报错!

正确示例:

typescript 复制代码
interface User {
  name: string;
}
interface Data {
  user: User;
}

function parseData(data: Data): string {
  return data.user.name.toUpperCase();
}

尽量避免使用 any,使用 unknown 或明确类型更安全。满屏幕使用any是专业性不足的表现

不写函数返回值类型

TypeScript 会自动推导返回值,但在复杂逻辑中,显式声明返回类型可以增强可读性和类型保护。笔者认为最重要的是为了维护

错误示例:

typescript 复制代码
function getUser(id: number) {
  if (id === 1) return 'admin';
  return null;
}

正确示例:

typescript 复制代码
function getUser(id: number): string | null {
  if (id === 1) return 'admin';
  return null;
}

显式声明返回类型是良好的代码习惯,尤其适用于公共函数库函数

Interface 和 Type 定义太随意 / 不抽离

Interface 和 Type 是 TS 中非常重要的两种类型,在使用他们的时候,命名非常非常重要。写临时类型难以复用和维护

错误示例:

typescript 复制代码
function login(user: { username: string; password: string }) {
  // ...
}

正确示例:

typescript 复制代码
interface LoginParams {
  username: string;
  password: string;
}

function login(user: LoginParams) {
  // ...
}

类型应当抽离,复用更方便,代码更清晰。

在对象或函数参数中直接使用类型断言

类型断言(Type Assertion)是 TypeScript 中的一种语法,表示你明确告诉编译器某个值的类型是什么,即使它当前的推导类型不是你说的这个。

它不会做任何实际的运行时转换,仅仅用于绕过编译器的类型检查,常见于你"确信"某个值是什么类型但 TypeScript 推断不出来时。

只有在特殊场景下才使用类型断言,类型断言会破坏类型自动推导

错误示例:

typescript 复制代码
const data = fetchData() as any;
const name = (data as { user: { name: string } }).user.name;

正确示例:

typescript 复制代码
interface UserData {
  user: {
    name: string;
  };
}

const data: UserData = fetchData();
const name = data.user.name;

类型断言不是万能钥匙,优先使用类型声明、接口、泛型。

不使用工具类型

TypeScript 提供了很多内置工具类型(如 Partial, Pick, Omit 等),可以简化代码并增强复用性。

错误示例:

typescript 复制代码
interface User {
  id: number;
  name: string;
  age: number;
}

type UserPreview = {
  id: number;
  name: string;
};

正确示例:

typescript 复制代码
type UserPreview = Pick<User, 'id' | 'name'>;

合理使用工具类型,写出更简洁更灵活的代码。

混用 interfacetype 不明确

两者功能类似,但存在一些差异,新手容易随意混用。

建议:

  • interface 定义对象结构。
  • type 做联合类型、工具类型等更灵活的组合。

错误示例:

typescript 复制代码
type User = {
  name: string;
};

interface User {
  age: number;
} // 冲突!

正确示例:

typescript 复制代码
interface User {
  name: string;
  age: number;
}

小结:

interface 用于结构定义,type 用于类型组合和增强。

不使用枚举(Enum)管理常量值

魔法字符串易出错、难维护,应该用枚举统一管理。

错误示例:

typescript 复制代码
function getRole(role: string) {
  if (role === 'admin') return '管理员';
}

正确示例:

typescript 复制代码
enum Role {
  Admin = 'admin',
  User = 'user',
}

function getRole(role: Role) {
  if (role === Role.Admin) return '管理员';
}

常量值统一管理,提高可维护性。

类型不匹配却强行通过断言

使用 as 并不会真正转换类型,只是"告诉 TypeScript 你信我"。

错误示例:

typescript 复制代码
const val = '123' as unknown as number;

正确示例:

typescript 复制代码
const val = Number('123'); // 类型安全的转换

类型转换要谨慎,as 不能解决逻辑错误。

类型重复,没用泛型抽象

多个函数或接口出现重复代码时,应抽象为泛型。

错误示例:

typescript 复制代码
function wrapString(value: string): string[] {
  return [value];
}

function wrapNumber(value: number): number[] {
  return [value];
}

正确示例:

typescript 复制代码
function wrap<T>(value: T): T[] {
  return [value];
}

泛型能让你的类型更具扩展性和复用性。

不启用 strict 模式

strict 是 TypeScript 中最核心的类型检查开关。关闭它会让很多问题"躲"过编译器。

正确做法:

tsconfig.json 中启用:

json 复制代码
{
  "compilerOptions": {
    "strict": true
  }
}

开启 strict 模式,是 TypeScript 真正发挥威力的前提。

忽视 IDE 的提示与错误

VSCode 等 IDE 通常会高亮潜在的类型问题,但很多新手视而不见。

错误示例:

typescript 复制代码
const name: string = 123; // TS 提示类型错误,但被忽略

编译器和 IDE 是你最好的朋友,请认真对待他们的提示。

忽视类型收窄(type narrowing)

类型收窄是 TypeScript 根据条件判断自动"缩小"变量的类型。

错误示例:

typescript 复制代码
function printLength(str: string | null) {
  return str.length; // 报错
}

正确示例:

typescript 复制代码
function printLength(str: string | null) {
  if (str) {
    return str.length;
  }
  return 0;
}

利用 typeof, in, instanceof 等收窄类型,避免错误。

忽略 undefinednull 的存在

TypeScript 默认不强制处理 nullundefined,需要手动开启 strictNullChecks

错误示例:

typescript 复制代码
function greet(name: string) {
  return 'Hello ' + name.toUpperCase(); // name 可能为 undefined
}

正确示例:

typescript 复制代码
function greet(name?: string) {
  return name ? 'Hello ' + name.toUpperCase() : 'Hello';
}

尽量避免写出不处理空值的代码,空值检查是常识。

忘记在对象访问前做空值判断

对象嵌套访问时,未做空值判断极易导致运行时错误。

错误示例:

typescript 复制代码
const username = user.profile.name;

正确示例:

typescript 复制代码
const username = user?.profile?.name ?? 'Anonymous';

善用可选链(?.)和空值合并运算符(??)提高代码健壮性。

使用泛型却不指定类型参数

TypeScript 中的泛型应显式传入类型,避免类型不明确或不被推导。

错误示例:

typescript 复制代码
const arr = Array(); // 类型为 any[]

正确示例:

typescript 复制代码
const arr: Array<number> = [];

显式指定泛型参数有助于代码的可读性和类型安全。

混用 =====

== 会进行隐式类型转换,容易出现意料之外的结果。

错误示例:

typescript 复制代码
if (value == null) {
  // 可能同时为 undefined 或 null
}

正确示例:

typescript 复制代码
if (value === null) {
  // 明确判断
}

在 TypeScript 中应始终使用 ===!==,杜绝隐式类型转换。

总结

写好 TypeScript 其实并不难,关键在于理解类型系统的设计意图,并养成良好的编码习惯

相关推荐
李是啥也不会6 分钟前
Vue 组件化开发
vue.js
宝耶12 分钟前
HTML:表格数据展示区
前端·html
程序员海军26 分钟前
一键把网站变成吉卜力风格的神器来了
前端·chatgpt
三原28 分钟前
前端微应用-乾坤(qiankun)原理分析-沙箱隔离(js)
前端·架构·前端框架
IT专家-大狗29 分钟前
Edge浏览器安卓版流畅度与广告拦截功能评测【不卡还净】
android·前端·edge
Kx…………39 分钟前
Day3:个人中心页面布局前端项目uniapp壁纸实战
前端·学习·uni-app·实战·项目
肠胃炎42 分钟前
认识Vue
前端·javascript·vue.js
七月丶1 小时前
🛠 用 Node.js 和 commander 快速搭建一个 CLI 工具骨架(gix 实战)
前端·后端·github
砖吐筷筷1 小时前
我理想的房间是什么样的丨去明日方舟 Only 玩 - 筷筷月报#18
前端·github
七月丶1 小时前
🔀 打造更智能的 Git 提交合并命令:gix merge 实战
前端·后端·github