面包屑图标 当前位置: 首页
AI资讯
热点详情

避免TypeScript代码审查中最常见的8个反模式

AI热点日报
AI热点日报时间:2026-08-05
热点解读

CodeReview中常见八个TypeScript反模式:any当万能胶、catch用any而非unknown、as断言代替类型守卫、枚举滥用、可选链滥用导致undefined扩散、interface与type混用无规则、过度类型体操、忽略strict配置。修复方法包括定义具体类型、使用类型守卫、统一团队规范、开启strict逐步修复等。

最近 Code Review 了组里三个新人的代码,发现同样的问题反复出现。

别再这样写TypeScript了——Code Review中最常见的8个反模式

不是逻辑错误——TypeScript 编译器会帮你抓。是那种能跑,但让接手的人想打人的写法。

这里总结出8个最常见的反模式。你可能正在写其中至少3个。

反模式1:any 当万能胶

// ❌ 遇到类型报错就any
const handleResponse = (data: any) => {
  return data.result.items.map((item: any) => item.name);
};

表面上看,这段代码没什么问题。但仔细想想:data 的结构变了呢?items 不存在了呢?name 改成 title 了呢?

TypeScript不会告诉你——因为你告诉它"我不在乎类型"。

// ✅ 花30秒定义类型
interface ApiResponse {
  result: {
    items: Array<{ name: string; id: number }>;
  };
}

const handleResponse = (data: ApiResponse) => {
  return data.result.items.map((item) => item.name);
};

原则:每多一个 any,你的 TypeScript 就退化成了带类型注释的 Ja vaScript。

如果实在不确定类型是什么——用 unknown,下一节会说为什么。

反模式2:try-catch 里用 any 而不是 unknown

// ❌ catch里用any
try {
  await fetchData();
} catch (error: any) {
  console.log(error.message);  // 如果error不是Error对象呢?
  console.log(error.response.status);  // 如果没有response呢?
}

catch 里的 error 可能是任何东西——不只是 Error 对象。有可能是字符串、null、甚至 undefined。

// ✅ 用unknown + 类型守卫
try {
  await fetchData();
} catch (error: unknown) {
  if (error instanceof Error) {
    console.log(error.message);
  }
  if (isAxiosError(error)) {
    console.log(error.response?.status);
  }
}

unknown 强制你在使用前做类型检查——any 则让你假装知道它是什么。

反模式3:as 断言代替类型守卫

// ❌ 到处用 as 强转
const user = response.data as User;
const element = document.getElementById('root') as HTMLDivElement;
const config = JSON.parse(text) as AppConfig;

as 的意思是"我比编译器更懂"。但你真的更懂吗?

如果 response.data 返回的不是 User 结构?如果那个 DOM 元素不存在或者不是 div运行时崩溃,TypeScript 不会预警。

// ✅ 用类型守卫做运行时检查
function isUser(data: unknown): data is User {
  return (
    typeof data === 'object' &&
    data !== null &&
    'id' in data &&
    'name' in data
  );
}

const data = response.data;
if (isUser(data)) {
  // 这里 data 被收窄为 User,编译器和运行时都安全
  console.log(data.name);
}

// DOM 元素用 instanceof
const element = document.getElementById('root');
if (element instanceof HTMLDivElement) {
  element.style.display = 'flex';
}

原则:as 是骗编译器,类型守卫是让编译器帮你验证。

唯一合理用 as 的场景:你能100%确定类型,且加守卫的成本不值得(比如测试代码里mock数据)。

反模式4:枚举滥用(该用 union type 的场景)

// ❌ 为了几个固定值搞个enum
enum Status {
  Active = 'active',
  Inactive = 'inactive',
  Pending = 'pending',
}

enum Direction {
  Up = 'up',
  Down = 'down',
  Left = 'left',
  Right = 'right',
}

enum 看着很规范,但它有两个问题:

  1. 编译后会生成额外的运行时代码(一个IIFE对象)
  2. 数字枚举是双向映射,容易出bug
// ✅ union type:零运行时开销,类型提示一样好
type Status = 'active' | 'inactive' | 'pending';
type Direction = 'up' | 'down' | 'left' | 'right';

// 需要遍历所有值?用 const 数组 + typeof
const STATUSES = ['active', 'inactive', 'pending'] as const;
type Status = typeof STATUSES[number];

什么时候用 enum: 需要反向映射(数字→名字)、或者值需要作为对象使用(Status.Active)且团队统一约定用 enum。其他场景 union type 更轻量。

反模式5:可选链?.滥用导致undefined地狱

// ❌ 一路?.到底,每个属性都加
const name = user?.profile?.settings?.displayName?.trim()?.toLowerCase();
// name 的类型是 string | undefined

const items = data?.response?.result?.items?.filter(i => i?.active);
// items 的类型是 Item[] | undefined

可选链是好东西,但滥用它等于在说:"我不确定这个数据结构长什么样。"

结果:每个变量都可能是 undefined,下游代码全都要加空值检查,undefined 像传染病一样扩散。

// ✅ 在入口处做一次空值检查,内部使用确定类型
function renderProfile(user: User | null) {
  if (!user) return ;
  
  // 过了守卫后,user 确定存在
  const { profile } = user;
  const displayName = profile.settings.displayName.trim().toLowerCase();
  // displayName 类型是 string,确定的
  return 

{displayName}

; }

原则:在边界层(API响应、props传入)做一次空值检查,内部逻辑用确定类型。不要让 ?. 变成"我懒得想数据结构"的借口。

反模式6:interface 和 type 混着用没规则

// ❌ 同一个项目里随机混用
interface UserProps {  // 这里用interface
  name: string;
}

type ButtonProps = {  // 这里又用type
  onClick: () => void;
}

interface ApiResponse {  // 又interface
  data: unknown;
}

type Theme = 'light' | 'dark';  // type

这不是语法错误,但没有一致性的代码让人读着累

// ✅ 团队约定一个规则并统一执行
// 规则示例(不是唯一正确答案,关键是统一):

// type 用于:联合类型、交叉类型、工具类型、简单别名
type Status = 'active' | 'inactive';
type Nullable = T | null;
type ButtonProps = { onClick: () => void; label: string };

// interface 用于:需要 extends 继承、第三方库声明合并
interface Repository {
  findById(id: string): Promise;
}
interface UserRepository extends Repository {
  findByEmail(email: string): Promise;
}

关键不是 interface 和 type 谁更好——而是你的项目有没有一个统一的规则。 没有规则 = 每次读代码都要猜"为什么这里用了 interface"。

反模式7:过度类型体操

// ❌ 简单场景用复杂泛型
type DeepPartial = {
  [P in keyof T]?: T[P] extends object
    ? T[P] extends Array
      ? Array>
      : DeepPartial
    : T[P];
};

type ExtractRouteParams =
  T extends `${infer _}:${infer Param}/${infer Rest}`
    ? { [K in Param]: string } & ExtractRouteParams
    : T extends `${infer _}:${infer Param}`
      ? { [K in Param]: string }
      : {};

// 用这些类型的地方只有2处调用

能写出来说明你TypeScript水平很高。但:

  1. 半年后你自己都看不懂
  2. 新人看到直接放弃理解
  3. IDE提示变成一坨不可读的展开类型
// ✅ 问自己:这个泛型用了几次?
// 如果只用1-2次,直接写具体类型

// 替代 DeepPartial:手动写需要partial的字段
interface UpdateUserInput {
  name?: string;
  profile?: {
    a vatar?: string;
    bio?: string;
  };
}

// 替代复杂路由泛型:直接定义参数类型
interface RouteParams {
  userId: string;
  postId: string;
}

原则:类型是给人读的,不是给人秀的。如果一个泛型需要3行以上的条件类型,先问问有没有更简单的写法。

反模式8:忽略 strict 配置

// ❌ tsconfig.json
{
  "compilerOptions": {
    "strict": false,  // "先关了,以后再开"
    // 或者更阴间的:
    "strict": true,
    "strictNullChecks": false,  // 开了strict又关掉最重要的子选项
    "noImplicitAny": false
  }
}

strictNullChecks: false 意味着 TypeScript 认为所有值都不可能是 null 或 undefined。这等于关掉了 TypeScript 最有价值的安全检查之一。

// strictNullChecks: false 时,这段代码不报错
const user = users.find(u => u.id === id);
console.log(user.name);  // user 可能是 undefined!运行时崩溃

// strictNullChecks: true 时,TypeScript 会逼你处理
const user = users.find(u => u.id === id);
if (!user) throw new Error(`User ${id} not found`);
console.log(user.name);  // 安全
// ✅ 新项目直接开strict,老项目逐步开
{
  "compilerOptions": {
    "strict": true
    // strict = 以下全部为true:
    // strictNullChecks, noImplicitAny, strictFunctionTypes,
    // strictBindCallApply, strictPropertyInitialization,
    // noImplicitThis, alwaysStrict, useUnknownInCatchVariables
  }
}

老项目怕一下全开报错太多?// @ts-expect-error 逐个标记,然后建一个 TODO 列表慢慢修。比永远关着 strict 强一万倍。

速查表

反模式 修复 一句话
any 当万能胶 定义具体类型 每个any都是定时冲击波
catch用any 用unknown+类型守卫 error可能是任何东西
as断言满天飞 类型守卫/instanceof as是骗编译器
enum滥用 union type + as const 零运行时开销
?.可选链滥用 入口处一次空值检查 不要让undefined扩散
interface/type混用 团队统一规则 一致性比选择更重要
过度类型体操 用具体类型代替 类型是给人读的
关strict 开strict逐步修 最有价值的安全网

你写了几个?

说实话,这8个我至少写过5个。特别是第1个和第3个——赶工期的时候 anyas 就是最快的"解决"方案。

但每次接手别人(或者三个月前的自己)充满 any 的代码时,就知道当初省的那30秒,现在要花30分钟来还。

你在 Code Review 中最常打回哪种写法?

热点追踪提示词
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:避免TypeScript代码审查中最常见的8个反模式要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
来源:https://segmentfault.com/a/1190000048117017
前端

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关热点
AI热点2026-08-05 14:59
全国仅4所高校入选工信部重要名单

工信部公布2025年人工智能应用典型案例285项,全国仅4所高校入选。北京大学和山东大学各有2个,哈尔滨工业大学和温州大学各有1个,彰显了高校在AI应用领域的创新实力。

AI热点2026-08-05 14:59
用AI汇报方案被老板夸思路清晰,只需一句话技巧

用AI扮演投资人角色审视方案,找出逻辑漏洞、数据缺乏对比和结论模糊的问题,重构后汇报仅15分钟,老板称赞思路清晰。核心在于让AI梳理逻辑而非代写,赋予角色、审查逻辑、极致精简,工具如AiPy的思维链可辅助搭建框架。

AI热点2026-08-05 14:59
DeepSeek与Claude联手打造逻辑无懈可击的悬疑漫剧

2025年悬疑漫剧创作中,采用DeepSeek与Claude双模型协同模式,由深度推理模型构建严密因果链,长文本模型润色氛围,使逻辑漏洞率从35%降至2 8%,单集剧本耗时缩短至15分钟以内,并需注意逻辑审讯与道具锁定等操作要点。

AI热点2026-08-05 14:59
AI漫剧吸睛核心法则 前3秒一句台词抓住观众

2025年短视频与AI漫剧竞争激烈,前3秒开场台词决定完播率。利用Grok实时热点感知和GPT-4o营销文案库,批量生成情绪钩子,使留存率从18 5%提升至42 1%,成本仅约0 05元。

延伸阅读