TypeScript 类型系统完全指南:从基础到高级工具类型(知识库版)

本文系统梳理 TypeScript 类型体系,覆盖原始类型、复合类型、内置工具类型到进阶类型机制,附代码示例与选型最佳实践,可作为前端 / 全栈开发的类型知识库归档。

一、为什么 TypeScript 需要类型系统

1.1 JavaScript 的动态类型痛点

JavaScript 是弱类型、动态类型语言,变量类型可以随时改变,错误只有运行时才会暴露:

js

运行

复制代码
// JS 不会报错,运行时才会出问题
function add(a, b) {
  return a + b;
}
add("1", 2); // 返回 "12",逻辑错误,编译期无任何提示

小型项目尚可接受,中大型项目中会导致:

  • 重构困难,改一个字段全靠人肉搜索
  • 接口字段不匹配,线上才爆错
  • 代码可读性差,参数含义全靠猜

1.2 TypeScript 静态类型的核心价值

TypeScript = JavaScript + 静态类型系统,在编译阶段做类型检查,不运行代码就能发现错误。 核心价值:

  1. 提前捕获错误:编译期拦截类型不匹配、字段缺失等问题
  2. 提升可维护性:类型即文档,看类型就知道数据结构
  3. 智能提示更强:IDE 自动补全、跳转定义、重构更安全
  4. 团队协作更稳:统一数据契约,减少沟通成本

1.3 类型注解基本语法

在变量、函数参数、函数返回值后用 : 类型 标注:

typescript

运行

复制代码
// 变量类型注解
let name: string = "张三";
let age: number = 25;

// 函数参数 + 返回值注解
function greet(name: string): string {
  return `Hello, ${name}`;
}

TS 支持类型推断:能自动推导类型的场景,不需要手动写注解。

typescript

运行

复制代码
// 自动推断为 string,无需手动写注解
let message = "hello world";

二、基础原始类型

TS 继承了 JS 的全部原始类型,并扩展了特殊类型。

2.1 常规原始类型

表格

类型 说明 示例
string 字符串 let s: string = "abc"
number 数字(整数、浮点数统一) let n: number = 100
boolean 布尔值 let flag: boolean = true
null 空值 let v: null = null
undefined 未定义 let u: undefined = undefined
symbol 唯一符号 let key: symbol = Symbol()
bigint 大整数 let big: bigint = 100n

注意:nullundefined 默认是所有类型的子类型(可赋值给任意类型),开启 strictNullChecks 后会严格限制,是生产环境推荐配置。

2.2 特殊原始类型

① any:任意类型

关闭类型检查,变量可以赋值任意类型,相当于退化成 JS。

typescript

运行

复制代码
let data: any = "hello";
data = 123;    // 不报错
data = true;   // 不报错
data.xxx();    // 调用不存在的方法也不报错

危害:失去所有类型保护,是 TS 中的「后门」,非必要不使用。

② unknown:安全的任意类型

unknown 是类型安全的 any。可以接收任意值,但不能直接操作,必须先做类型判断 / 断言才能使用。

typescript

运行

复制代码
let val: unknown = 100;
// val + 10; ❌ 直接报错,不能操作 unknown
if (typeof val === "number") {
  console.log(val + 10); // ✅ 类型守卫后可用
}

选型建议 :不确定类型时,优先用 unknown 代替 any

③ void:无返回值

用于函数,代表函数没有返回值。

typescript

运行

复制代码
function log(msg: string): void {
  console.log(msg);
  // 不需要 return,或 return 空
}

④ never:永不存在的值

代表永远不会有返回的类型,常见两种场景:

  1. 抛出异常的函数
  2. 无限循环的函数
  3. 联合类型穷尽检查的兜底

typescript

运行

复制代码
// 抛出异常,永远不会正常返回
function throwError(msg: string): never {
  throw new Error(msg);
}

三、复合类型

3.1 数组类型

两种写法,效果完全一致,推荐第一种:

typescript

运行

复制代码
// 写法1:类型 + [](最常用)
let nums: number[] = [1, 2, 3];
let names: string[] = ["a", "b"];

// 写法2:泛型数组
let nums2: Array<number> = [1, 2, 3];

3.2 元组 Tuple

固定长度、固定每个位置类型的数组。

typescript

运行

复制代码
// 第一个元素 string,第二个 number,长度固定为2
let user: [string, number] = ["张三", 25];

// 场景:函数返回多个值
function getUserInfo(): [string, number] {
  return ["李四", 30];
}

3.3 对象类型:type 与 interface

TS 有两种方式定义对象结构:type(类型别名)和 interface(接口)。

① type 类型别名

typescript

运行

复制代码
type User = {
  id: number;
  name: string;
  age?: number; // ? 代表可选属性
  readonly email: string; // readonly 代表只读,不可修改
};

const u: User = {
  id: 1,
  name: "王五",
  email: "wang@test.com"
};

② interface 接口

typescript

运行

复制代码
interface Product {
  id: number;
  title: string;
  price: number;
  desc?: string;
}

const p: Product = {
  id: 101,
  title: "手机",
  price: 2999
};

③ type vs interface 核心区别

表格

特性 type interface
定义对象
定义联合 / 交叉 / 元组 / 函数类型
声明合并(重复定义自动合并)
继承扩展 通过 & 交叉类型 通过 extends
映射类型、条件类型

④ 选型建议

  • 优先用 interface 定义对象、类的结构,扩展性更好,支持声明合并
  • 用 type 定义联合类型、交叉类型、工具类型、元组、函数类型
  • 简单对象二者均可,团队统一风格即可

3.4 联合类型与交叉类型

① 联合类型 |

变量可以是多种类型中的一种:

typescript

运行

复制代码
let status: "pending" | "success" | "error"; // 字面量联合
status = "success";

let id: string | number;
id = 100;
id = "abc";

② 交叉类型 &

将多个类型合并为一个,拥有所有属性:

typescript

运行

复制代码
type Base = { id: number };
type Time = { createTime: string };
type RecordItem = Base & Time; // 同时拥有 id 和 createTime

3.5 函数类型

完整描述参数类型和返回值类型:

typescript

运行

复制代码
// 直接定义
type AddFn = (a: number, b: number) => number;

const add: AddFn = (a, b) => a + b;

// 可选参数
function greet(name: string, prefix?: string): string {
  return prefix ? `${prefix} ${name}` : name;
}

// 剩余参数
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0);
}

3.6 枚举 enum

定义一组命名的常量,分为数字枚举和字符串枚举。

typescript

运行

复制代码
// 数字枚举:默认从 0 开始自增
enum Status {
  Pending,  // 0
  Success,  // 1
  Error     // 2
}

// 字符串枚举
enum OrderStatus {
  Created = "created",
  Paid = "paid",
  Shipped = "shipped"
}

注意:枚举会编译成实际的 JS 对象,增加代码体积。简单场景推荐用字面量联合类型替代枚举,更轻量。


四、内置高级工具类型(Utility Types)

TS 内置了一批常用的类型转换工具,基于泛型实现,日常开发高频使用。

4.1 Partial<T>:所有属性变为可选

typescript

运行

复制代码
interface User { id: number; name: string; age: number }
type PartialUser = Partial<User>;
// 等价于 { id?: number; name?: string; age?: number }

场景:更新对象时,只传部分字段。

4.2 Required<T>:所有属性变为必填

typescript

运行

复制代码
type RequiredUser = Required<PartialUser>;
// 所有可选属性变回必填

4.3 Readonly<T>:所有属性变为只读

typescript

运行

复制代码
type ReadonlyUser = Readonly<User>;
// 所有属性只能读,不能修改

4.4 Pick<T, K>:选取部分属性

typescript

运行

复制代码
type UserSimple = Pick<User, "id" | "name">;
// 等价于 { id: number; name: string }

场景:精简大对象,只取需要的字段。

4.5 Omit<T, K>:排除部分属性

typescript

运行

复制代码
type UserWithoutAge = Omit<User, "age">;
// 等价于 { id: number; name: string }

4.6 Record<K, T>:定义键值对类型

typescript

运行

复制代码
// 键是 string,值是 number
type ScoreMap = Record<string, number>;
const scores: ScoreMap = { math: 90, english: 85 };

4.7 Exclude<T, U>:联合类型排除

typescript

运行

复制代码
type Status = "a" | "b" | "c";
type StatusWithoutC = Exclude<Status, "c">; // "a" | "b"

4.8 Extract<T, U>:联合类型提取交集

typescript

运行

复制代码
type A = "a" | "b" | "c";
type B = "b" | "c" | "d";
type Common = Extract<A, B>; // "b" | "c"

4.9 ReturnType<T>:获取函数返回值类型

typescript

运行

复制代码
function getUser() {
  return { id: 1, name: "张三" };
}
type UserType = ReturnType<typeof getUser>;
// { id: number; name: string }

4.10 Parameters<T>:获取函数参数类型元组

typescript

运行

复制代码
type AddParams = Parameters<typeof add>;
// [number, number]

五、进阶类型机制

5.1 类型守卫

缩小联合类型的范围,让 TS 识别具体类型:

typescript

运行

复制代码
// typeof 守卫
function print(val: string | number) {
  if (typeof val === "string") {
    console.log(val.length); // 识别为 string
  } else {
    console.log(val.toFixed(2)); // 识别为 number
  }
}

// in 守卫:判断对象是否包含某属性
interface Dog { bark(): void }
interface Cat { meow(): void }
function speak(animal: Dog | Cat) {
  if ("bark" in animal) {
    animal.bark();
  } else {
    animal.meow();
  }
}

5.2 类型断言 as

手动告诉 TS 「我确定这个值是什么类型」,跳过检查。

typescript

运行

复制代码
const input = document.getElementById("input") as HTMLInputElement;
input.value; // 直接访问 input 专属属性

注意:类型断言有风险,确保类型正确再使用,避免滥用。

5.3 条件类型

类似三元运算符,根据类型判断返回不同类型:

typescript

运行

复制代码
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false

内置工具类型大多基于条件类型实现。

5.4 映射类型

遍历已有类型的键,生成新类型:

typescript

运行

复制代码
// 把所有属性变为 string
type AllString<T> = {
  [K in keyof T]: string;
};

5.5 常用操作符

  • keyof:获取对象类型的所有键,返回联合类型

    typescript

    运行

    复制代码
    interface User { id: number; name: string }
    type Keys = keyof User; // "id" | "name"
  • typeof:获取值的类型

    typescript

    运行

    复制代码
    const obj = { a: 1, b: "2" };
    type ObjType = typeof obj; // { a: number; b: string }
  • as const:将值断言为只读字面量类型

    typescript

    运行

    复制代码
    const arr = ["a", "b"] as const;
    type ArrType = typeof arr; // readonly ["a", "b"]

六、最佳实践与避坑

  1. 尽量不用 any ,不确定类型优先用 unknown + 类型守卫
  2. 对象优先 interface ,联合 / 工具类型用 type,保持风格统一
  3. 开启严格模式tsconfig.jsonstrict: true,获得最强类型检查
  4. 避免过度类型体操:过于复杂的嵌套类型会降低可读性,适当拆分
  5. 少用枚举:简单场景用字面量联合类型,更轻量无运行时代价
  6. 类型断言要谨慎:只在你比 TS 更清楚类型时使用,不要用来「掩盖」错误

七、全文总结

TypeScript 的类型系统是其核心价值所在:

  • 基础类型 覆盖 JS 全部原始值,补充了 any/unknown/never/void 等特殊类型
  • 复合类型通过对象、数组、元组、联合、交叉描述复杂数据结构
  • 内置工具类型提供开箱即用的类型转换能力,覆盖 90% 日常场景
  • 进阶机制支持条件、映射等高级操作,满足复杂类型需求

合理使用类型系统,能在不损失 JS 灵活性的前提下,大幅提升代码质量、可维护性与团队协作效率,是中大型前端项目的标配。

相关推荐
CQU_JIAKE1 小时前
7.23[a]
linux·运维·服务器
想学好C++的oMen1 小时前
socket编程TCP
linux·网络·网络协议·tcp/ip
ShirleyWang0121 小时前
Linux中Vim编辑器快速找到需要改的行
linux·编辑器·vim
weixin_457340212 小时前
ssh 本地链接服务器地址和服务器查看本地地址
运维·服务器·ssh
MXsoft6183 小时前
在大型混合云网络环境中,如何高效实现自动化运维?
运维·网络·自动化
盐焗鹌鹑蛋3 小时前
【Linux】基本指令
linux
海阔天空任鸟飞~10 小时前
Linux 权限 777
linux·运维·服务器
IT瑞先生11 小时前
docker-compose下快速部署实操——持续更新...
运维·docker·容器
无锡银洲自动化12 小时前
工业模拟量采集痛点分析:IDCB-4E/DR/Y测量前端解决方案
运维·产品运营