在日常前端开发中,TypeScript 给我们带来的最大好处,就是 类型安全智能提示
不过,很多同学一看到「交叉类型」「映射类型」这些名词就有点发怵。其实,它们没有那么玄乎,只要搞懂概念 + 使用场景,就能灵活运用到项目里。

本文带你用通俗的语言理解以下几个常见类型:

  • 交叉类型(&
  • 联合类型(|
  • 类型别名(type
  • 类型索引(keyof、索引访问)
  • 类型约束(extends
  • 映射类型({ [K in ...]: ... }
  • 条件类型(T extends U ? X : Y
  • 工具类型:PartialReadonlyPickRecord
  • 泛型

1. 交叉类型(Intersection Types)

👉 概念:把多个类型合并成一个,要求同时满足。

type Person = { name: string }
type Worker = { job: string }

type Employee = Person & Worker
// 等价于 { name: string; job: string }

const x: Employee = { name: "张三", job: "程序员" }

通俗理解
A 和 B 的交集,既要满足 A,又要满足 B。
在项目里,经常用来「组合多个对象的属性」。


2. 联合类型(Union Types)

👉 概念:一个值可以是几种类型之一。

let id: string | number
id = 123
id = "abc"

通俗理解
A 或 B,灵活选择一个。
场景:接口的返回值可能是「成功结果」或「错误信息」。

type Success = { code: 200; data: string }
type Fail = { code: 500; error: string }

type Response = Success | Fail

3. 类型别名(Type Aliases)

👉 概念:给复杂的类型起一个名字,方便复用。

type ID = string | number
type User = { id: ID; name: string }

通俗理解
相当于给复杂的表达式起「变量名」。
比如 string | number 以后直接叫 ID,写代码更清爽。


4. 类型索引(Index Types)

👉 概念:从类型里「取出键」或「取出键的值类型」。

type User = { id: number; name: string; age: number }

type UserKeys = keyof User   // "id" | "name" | "age"
type UserName = User["name"] // string

通俗理解

  • keyof:取对象的所有 key。
  • T[K]:取某个 key 对应的类型。

在写「通用函数」的时候特别好用。


5. 类型约束(Type Constraints)

👉 概念:通过 extends 限制泛型必须满足某些条件。

function getProp<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}

const user = { id: 1, name: "张三" }
getProp(user, "name") // ✅ string
// getProp(user, "age") // ❌ 报错

通俗理解
extends 就像给类型加了个「条件过滤器」,不符合就报错。
常用于工具函数里,让输入更安全。


6. 映射类型(Mapped Types)

👉 概念:基于已有类型,批量生成新的类型。

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

type PartialUser = {
  [K in keyof User]?: User[K]
}
// 等价于 { id?: number; name?: string }

TypeScript 已经内置了很多映射类型,比如:

  • Partial<T>:把所有属性变成可选
  • Readonly<T>:把所有属性变成只读

通俗理解
像「for…in」循环那样,把一个类型改造成另一个。


7. 条件类型(Conditional Types)

👉 概念:根据条件返回不同类型。

type IsString<T> = T extends string ? "yes" : "no"

type A = IsString<string>  // "yes"
type B = IsString<number>  // "no"

通俗理解
类型里的 if...else
常见于工具类型,比如提取某些字段:

type ExtractPromise<T> = T extends Promise<infer U> ? U : T

type A = ExtractPromise<Promise<number>> // number
type B = ExtractPromise<string>          // string

8. 工具类型

1️⃣ Partial —— 可选属性

通俗理解:把对象类型里所有属性都变成 可选

  • 就像给对象开了“可选开关”,属性可以不用填。

示例

interface User {
  id: number;
  name: string;
  age: number;
}

type PartialUser = Partial<User>;

const user1: PartialUser = {}; // ✅ 全部可选
const user2: PartialUser = { id: 1 }; // ✅ 可以只写部分属性

用途

  • 用在更新接口,用户可能只改部分字段
  • 表单可选项类型定义

2️⃣ Readonly —— 只读属性

通俗理解:把对象类型里所有属性都变成 只读,不能被修改。

  • 就像给对象加了锁,属性只能读不能写。

示例

type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = { id: 1, name: "Alice", age: 20 };
user.id = 2; // ❌ 报错:无法赋值给 "id"

用途

  • 防止修改配置对象
  • Redux/状态管理里的不可变数据

3️⃣ Pick<T, K> —— 挑选属性

通俗理解:从对象类型里 挑出你想要的属性

  • 就像在超市里挑选商品,只留下你需要的几件。

示例

type UserName = Pick<User, "name" | "id">;

const user: UserName = { id: 1, name: "Alice" }; // ✅
const user2: UserName = { id: 1, age: 20 }; // ❌ 报错:没有 name 属性

用途

  • 做接口返回值限制,只返回部分字段
  • 避免传输冗余数据

4️⃣ Record<K, T> —— 生成对象类型

通俗理解:创建一个对象类型,键都是 K,值都是 T

  • 就像给你一个模板,把每个 key 的值类型统一定义好

示例

type Roles = "admin" | "user" | "guest";

type RoleMap = Record<Roles, string>;

const roleMap: RoleMap = {
  admin: "管理员",
  user: "普通用户",
  guest: "游客"
};

用途

  • 构建字典对象
  • 定义配置表、状态映射表

9. 泛型(Generics)

👉 概念:在定义函数、接口或类型时,不直接指定具体类型,而是用一个「占位符」表示类型,调用时再确定。

function identity<T>(value: T): T {
  return value
}

const num = identity(123)     // 类型推断为 number
const str = identity("hello") // 类型推断为 string

通俗理解

  • 泛型就是「类型的变量」,让代码更灵活复用。
  • 就像函数里的参数一样,类型也可以先占位,使用时再确定。

泛型在项目里的高频用法

  1. 通用函数
function getFirstItem<T>(arr: T[]): T | undefined {
  return arr[0]
}

const firstNum = getFirstItem([1, 2, 3])      // number
const firstStr = getFirstItem(["a", "b"])     // string
  1. 通用接口 / 类型
interface ApiResponse<T> {
  code: number
  data: T
  message?: string
}

type UserResponse = ApiResponse<{ id: number; name: string }>
  1. 配合类型约束
function getProp<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}
  1. 与条件类型结合(高级用法):
type Unpack<T> = T extends Promise<infer U> ? U : T

type A = Unpack<Promise<number>> // number
type B = Unpack<string>          // string

一句话记忆法:

  • 泛型 = 「类型参数」,先留空,调用时填上
  • <T> 是类型的占位符
  • extends 给泛型加条件
  • 配合条件类型可做高级类型运算

🔗 总结

类型 符号 用途
交叉类型 & 合并多个类型
联合类型 ` ` 多个类型之一
类型别名 type 给复杂类型起名
类型索引 keyof / T[K] 获取键或值的类型
类型约束 extends 限制泛型范围
映射类型 { [K in keyof T]: ... } 批量生成新类型
条件类型 T extends U ? X : Y 类型里的 if/else
工具类型 Partial / Readonly / Pick / Record 属性可选/只读/挑选/生成字典映射

💡 一句话记忆法

  • & 是「并且」
  • | 是「或者」
  • type 是「取个名字」
  • keyof 是「拿所有 key」
  • extends 是「加个条件」
  • 映射类型是「for…in」
  • 条件类型是「if…else」
  • 工具类型 → 快速生成常用类型
  • 泛型占位符

更多推荐