跳到主要内容
返回··1 分钟·技术

TypeScript 类型体操:让代码更安全

TypeScript 的类型系统是图灵完备的。本文分享 5 个让代码更健壮的类型技巧。

TypeScript 类型体操:让代码更安全

TypeScript 不只是给 JavaScript 加类型。它的类型系统是图灵完备的,可以做很多强大的事情。

一、用 satisfies 保证类型安全

// ❌ 容易丢失字面量类型
const config: Config = {
  api: '/users',
  timeout: 5000,
};
config.api;  // 类型是 string,不是字面量 '/users'

// ✅ 保留字面量类型,同时校验结构
const config = {
  api: '/users',
  timeout: 5000,
} satisfies Config;
config.api;  // 类型是 '/users'

二、用 as const 锁定常量

const STATUS = {
  PENDING: 'pending',
  SUCCESS: 'success',
  ERROR: 'error',
} as const;

// 类型是 'pending' | 'success' | 'error',而不是 string
type Status = typeof STATUS[keyof typeof STATUS];

三、用模板字面量类型生成路径

type ApiPaths =
  | '/users'
  | '/users/:id'
  | '/posts'
  | '/posts/:id';

// 自动生成所有路径
type ExtractParams<T extends string> =
  T extends `${string}:${infer P}` ? P : never;

type ParamsOf<T extends string> =
  T extends `${string}:${infer P}/${infer Rest}`
    ? P | ParamsOf<Rest>
    : T extends `${string}:${infer P}`
      ? P
      : never;

type UserParams = ParamsOf<'/users/:id/posts/:postId'>;
// type UserParams = 'id' | 'postId'

四、用 Zod 在运行时校验

import { z } from 'zod';

const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().int().positive().optional(),
});

type User = z.infer<typeof UserSchema>;

function createUser(data: unknown): User {
  return UserSchema.parse(data);  // 运行时校验 + 类型推导
}

五、用类型守卫收窄类型

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

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

type Shape = Circle | Square;

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.sideLength ** 2;
  }
}

六、用 Pick/Omit 派生类型

interface User {
  id: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// 不包含敏感字段的公开类型
type PublicUser = Omit<User, 'password'>;

// 创建用户时的输入类型
type CreateUserInput = Pick<User, 'name' | 'email'> & {
  password: string;
};

七、用 Record 构造映射类型

type Role = 'admin' | 'user' | 'guest';
type Permissions = Record<Role, string[]>;

// 类型为:
// {
//   admin: string[];
//   user: string[];
//   guest: string[];
// }

const perms: Permissions = {
  admin: ['read', 'write', 'delete'],
  user: ['read', 'write'],
  guest: ['read'],
};

写在最后

好的类型设计能让代码自我解释

类型不是束缚,而是文档。

当你的类型设计得当时,IDE 能给你精确的提示,重构也变得更安全。这才是 TypeScript 的真正威力。

希望这些技巧对你有帮助! 🎯

回到首页感谢阅读 · 欢迎在下方留言

相关文章