公司动态
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 静态类型系统在编译阶段做类型检查不运行代码就能发现错误。 核心价值提前捕获错误编译期拦截类型不匹配、字段缺失等问题提升可维护性类型即文档看类型就知道数据结构智能提示更强IDE 自动补全、跳转定义、重构更安全团队协作更稳统一数据契约减少沟通成本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 abcnumber数字整数、浮点数统一let n: number 100boolean布尔值let flag: boolean truenull空值let v: null nullundefined未定义let u: undefined undefinedsymbol唯一符号let key: symbol Symbol()bigint大整数let big: bigint 100n注意null和undefined默认是所有类型的子类型可赋值给任意类型开启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永不存在的值代表永远不会有返回的类型常见两种场景抛出异常的函数无限循环的函数联合类型穷尽检查的兜底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: Arraynumber [1, 2, 3];3.2 元组 Tuple固定长度、固定每个位置类型的数组。typescript运行// 第一个元素 string第二个 number长度固定为2 let user: [string, number] [张三, 25]; // 场景函数返回多个值 function getUserInfo(): [string, number] { return [李四, 30]; }3.3 对象类型type 与 interfaceTS 有两种方式定义对象结构type类型别名和interface接口。① type 类型别名typescript运行type User { id: number; name: string; age?: number; // ? 代表可选属性 readonly email: string; // readonly 代表只读不可修改 }; const u: User { id: 1, name: 王五, email: wangtest.com };② interface 接口typescript运行interface Product { id: number; title: string; price: number; desc?: string; } const p: Product { id: 101, title: 手机, price: 2999 };③ type vs interface 核心区别表格特性typeinterface定义对象✅✅定义联合 / 交叉 / 元组 / 函数类型✅❌声明合并重复定义自动合并❌✅继承扩展通过交叉类型通过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 和 createTime3.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 TypesTS 内置了一批常用的类型转换工具基于泛型实现日常开发高频使用。4.1 PartialT所有属性变为可选typescript运行interface User { id: number; name: string; age: number } type PartialUser PartialUser; // 等价于 { id?: number; name?: string; age?: number }场景更新对象时只传部分字段。4.2 RequiredT所有属性变为必填typescript运行type RequiredUser RequiredPartialUser; // 所有可选属性变回必填4.3 ReadonlyT所有属性变为只读typescript运行type ReadonlyUser ReadonlyUser; // 所有属性只能读不能修改4.4 PickT, K选取部分属性typescript运行type UserSimple PickUser, id | name; // 等价于 { id: number; name: string }场景精简大对象只取需要的字段。4.5 OmitT, K排除部分属性typescript运行type UserWithoutAge OmitUser, age; // 等价于 { id: number; name: string }4.6 RecordK, T定义键值对类型typescript运行// 键是 string值是 number type ScoreMap Recordstring, number; const scores: ScoreMap { math: 90, english: 85 };4.7 ExcludeT, U联合类型排除typescript运行type Status a | b | c; type StatusWithoutC ExcludeStatus, c; // a | b4.8 ExtractT, U联合类型提取交集typescript运行type A a | b | c; type B b | c | d; type Common ExtractA, B; // b | c4.9 ReturnTypeT获取函数返回值类型typescript运行function getUser() { return { id: 1, name: 张三 }; } type UserType ReturnTypetypeof getUser; // { id: number; name: string }4.10 ParametersT获取函数参数类型元组typescript运行type AddParams Parameterstypeof 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 IsStringT T extends string ? true : false; type A IsStringstring; // true type B IsStringnumber; // false内置工具类型大多基于条件类型实现。5.4 映射类型遍历已有类型的键生成新类型typescript运行// 把所有属性变为 string type AllStringT { [K in keyof T]: string; };5.5 常用操作符keyof获取对象类型的所有键返回联合类型typescript运行interface User { id: number; name: string } type Keys keyof User; // id | nametypeof获取值的类型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]六、最佳实践与避坑尽量不用any不确定类型优先用unknown 类型守卫对象优先interface联合 / 工具类型用type保持风格统一开启严格模式tsconfig.json中strict: true获得最强类型检查避免过度类型体操过于复杂的嵌套类型会降低可读性适当拆分少用枚举简单场景用字面量联合类型更轻量无运行时代价类型断言要谨慎只在你比 TS 更清楚类型时使用不要用来「掩盖」错误七、全文总结TypeScript 的类型系统是其核心价值所在基础类型覆盖 JS 全部原始值补充了any/unknown/never/void等特殊类型复合类型通过对象、数组、元组、联合、交叉描述复杂数据结构内置工具类型提供开箱即用的类型转换能力覆盖 90% 日常场景进阶机制支持条件、映射等高级操作满足复杂类型需求合理使用类型系统能在不损失 JS 灵活性的前提下大幅提升代码质量、可维护性与团队协作效率是中大型前端项目的标配。