前端TypeScript高级技巧:让你的代码更安全

前端TypeScript高级技巧:让你的代码更安全

毒舌时刻

前端TypeScript?这不是增加工作量吗?

"JavaScript就够了,为什么要用TypeScript"------结果类型错误频发,调试困难,

"TypeScript太严格了,我写起来很麻烦"------结果代码质量差,维护困难,

"我只在关键地方用TypeScript,其他地方用any"------结果失去了TypeScript的意义。

醒醒吧,TypeScript不是负担,而是提高代码质量的利器!

为什么你需要这个?

  • 类型安全:在编译时发现类型错误
  • 代码提示:提供更好的IDE智能提示
  • 重构安全:重构代码时更加安全
  • 可读性:代码更加清晰易懂
  • 可维护性:减少运行时错误,提高代码可维护性

反面教材

typescript 复制代码
// 反面教材:过度使用any
function processData(data: any) {
  // 没有类型检查,容易出错
  return data.name.toUpperCase();
}

// 反面教材:类型定义不完整
interface User {
  id: number;
  name: string;
  // 缺少email等其他属性
}

// 反面教材:类型断言滥用
function getUser(id: number): User {
  // 不安全的类型断言
  return fetch(`/api/users/${id}`).then(res => res.json()) as unknown as User;
}

正确的做法

typescript 复制代码
// 正确的做法:使用泛型
function identity<T>(arg: T): T {
  return arg;
}

// 使用泛型约束
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

// 正确的做法:使用联合类型和类型守卫
type Shape = Circle | Square;

interface Circle {
  kind: 'circle';
  radius: number;
}

interface Square {
  kind: 'square';
  sideLength: number;
}

function getArea(shape: Shape): number {
  // 类型守卫
  if (shape.kind === 'circle') {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.sideLength ** 2;
  }
}

// 正确的做法:使用类型推断
const user = {
  id: 1,
  name: '张三',
  email: 'zhangsan@example.com'
};

// TypeScript会自动推断user的类型

// 正确的做法:使用映射类型
interface Person {
  name: string;
  age: number;
}

// 生成只读类型
type ReadonlyPerson = Readonly<Person>;

// 生成可选类型
type PartialPerson = Partial<Person>;

// 生成必填类型
type RequiredPerson = Required<PartialPerson>;

// 正确的做法:使用条件类型
// 提取Promise的返回类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

// 测试
async function fetchData(): Promise<string> {
  return 'data';
}

// 类型会被推断为string
let data: UnwrapPromise<ReturnType<typeof fetchData>>;

// 正确的做法:使用模板字面量类型
type EventName<T extends string> = `${T}Changed`;
type MouseEventName = EventName<'click' | 'mouseover' | 'mouseout'>;
// 类型为 'clickChanged' | 'mouseoverChanged' | 'mouseoutChanged'

// 正确的做法:使用类型别名和接口
// 类型别名

type UserID = number;
type UserName = string;
type Email = string;

// 接口
interface User {
  id: UserID;
  name: UserName;
  email: Email;
  createdAt: Date;
  updatedAt: Date;
}

// 正确的做法:使用枚举
enum Role {
  Admin = 'admin',
  User = 'user',
  Guest = 'guest'
}

function checkPermission(role: Role): boolean {
  return role === Role.Admin;
}

// 正确的做法:使用命名空间
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }

  const lettersRegexp = /^[A-Za-z]+$/;
  const numberRegexp = /^[0-9]+$/;

  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s:
相关推荐
IPIPD4 分钟前
Node.js请求遇到503怎么重试?先解析Retry-After,再做有上限退避
前端
葡萄城技术团队11 分钟前
dsh-spreadjs-editor 的集成链路:把 SpreadJS Designer 嵌进 Agent 工作台
前端
FlyWIHTSKY1 小时前
vue2和vue3有什么区别,用法上有哪些区别
前端·javascript·vue.js
码云之上1 小时前
10 颗一模一样的「Edit」:中后台 Web Agent 怎么找到对的那一行
前端·人工智能·浏览器
量化分析码农2 小时前
【Python量化多因子实战 04】因子暴露不是 alpha:市值与行业中性化实战
前端·后端
不可能片场2 小时前
Electron 发布 正文写入的三条通道与读回口径
前端·electron
jerrywus2 小时前
让 AI 帮你部署 Vercel,报错了也不用手动搬日志
前端·agent·mcp
补码缩写2 小时前
11 行 Python 拆 PNG 块,解压后的字节数能手算
前端
coding漫漫长路2 小时前
PNG压缩先看图是哪一类,先无损再量化多半白做
前端
用户257680763212 小时前
搜「洗牙」为什么搜不到「洁治」
前端