Skip to content

TypeScript 知识体系导图(检索提要)

一、TS 基础核心(入门与进阶)

1. TS核心基础认知

  • 定义:TypeScript(TS)是JavaScript(JS)的超集,在JS基础上添加了静态类型系统,由微软开发,可编译为纯JS运行,核心价值是“类型安全”,避免运行时错误,提升代码可维护性和开发效率。

  • TS 与 JS 的区别:

    • 类型系统:TS有静态类型(编译期检查类型),JS是动态类型(运行期检查类型)。

    • 报错时机:TS在编译期报错(提前暴露问题),JS在运行期报错(线上易出问题)。

    • 功能拓展:TS新增接口、泛型、枚举、类的高级特性等,JS无相关原生支持。

    • 兼容性:TS可兼容所有JS语法,JS代码可直接在TS环境中运行;TS需编译为JS才能在浏览器/Node.js中运行。

  • TS 的核心优势(概要):

    • 类型安全:提前检查类型错误,减少线上Bug,降低调试成本。

    • 代码提示:开发时提供精准的代码补全、接口提示,提升开发效率。

    • 可维护性:类型注解让代码语义更清晰,便于团队协作和后期维护、重构。

    • 生态完善:兼容Vue、React、Node.js等主流前端技术栈,支持所有JS库。

  • TS 的编译流程:TS 源码 → 类型检查 → 编译为 JS(经 tsc)→ 在浏览器或 Node.js 中运行。

2. 基础类型(常用类型与易混点)

  • 原始类型:

    • 核心类型:string、number、boolean、null、undefined、symbol、bigint(ES2020 起为 ECMAScript 标准,TS 支持)。

    • 关键细节:

      • null 和 undefined:在 关闭 strictNullChecks(不推荐)时,历史上可视为广泛可赋值;开启 strictNullChecksstrict 默认包含)后,一般不能隐式赋给 string 等,需写成联合类型(如 string | null)。

      • symbol:唯一且不可变,常用于对象属性的唯一标识,TS支持symbol类型注解。

      • bigint:用于表示大整数(超过Number.MAX_SAFE_INTEGER),类型注解为bigint(如const num: bigint = 10n)。

  • 任意类型(any,易踩坑):

    • 定义:any类型可以表示任意类型,关闭类型检查,TS会忽略该变量的所有类型错误。

    • 使用场景:临时兼容旧JS代码、不确定变量类型时(尽量少用,否则失去TS核心价值)。

    • 坑点:any会“污染”其他变量(如any类型的变量赋值给其他类型,会导致其他变量也变为any)。

  • 未知类型(unknown):

    • 定义:unknown是“安全版的any”,表示未知类型,不能直接赋值给其他类型(需先类型断言或类型缩小)。

    • 与any的区别:unknown更安全,any可以随意调用属性/方法,unknown不行(需先确认类型)。

    • 典型用法:接收未知类型的入参(如接口返回体),在分支内先收窄再使用,避免写成 any。

  • 空类型(void):

    • 定义:表示没有返回值的函数(如函数返回undefined、null,或无return语句)。

    • 注意:void不能赋值给其他类型(除了any和unknown),与undefined的区别:undefined是值,void是类型。

  • never 类型(表示“不可达”,常用于穷尽性检查与兜底分支):

    • 定义:表示永远不会发生的类型(如函数永远不会返回、永远抛出错误)。

    • 应用场景:

      • 函数抛出错误(如function error(): never { throw new Error('错误'); })。

      • 无限循环(如function loop(): never { while(true) {} })。

      • 类型收窄的兜底(如switch-case的default,确保所有情况都被覆盖)。

3. 类型注解与类型推断

  • 类型注解(显式声明):

    • 定义:手动为变量、函数参数、返回值指定类型(格式:变量名: 类型)。

    • 示例:const name: string = '张三'; function add(a: number, b: number): number { return a + b; }

    • 适用场景:变量初始化时类型不明确、函数参数/返回值需要明确约束。

  • 类型推断(隐式声明):

    • 定义:TS会根据变量的初始化值、函数的返回值,自动推断出变量/函数的类型,无需手动注解。

    • 示例:const age = 20; // TS推断age为number类型;function sum(a: number, b: number) { return a + b; } // 推断返回值为number。

    • 优势:减少冗余代码,提升开发效率;注意:推断不明确时(如let x;),会推断为any类型。

  • 核心原则:能推断则不注解,不能推断则必须注解(如函数参数、未知类型的变量)。

二、TS 高级类型

1. 联合类型与交叉类型

  • 联合类型(|,“或”关系):

    • 定义:表示变量可以是多种类型中的一种(格式:类型1 | 类型2 | ...)。

    • 示例:const value: string | number = 10; // value可以是string或number。

    • 关键细节:联合类型的变量,只能访问所有类型的“公共属性/方法”(如string和number的公共方法只有toString())。

    • 类型收窄:通过判断语句(如 typeof、instanceof),把联合类型缩小为具体类型,从而安全访问该类型的专属属性。

      • 示例:if (typeof value === 'string') { console.log(value.length); } // 此时value被收窄为string类型。
  • 交叉类型(&,“且”关系):

    • 定义:表示变量同时具备多种类型的属性和方法(格式:类型1 & 类型2 & ...),常用于对象合并。

    • 示例:type A = { name: string }; type B = { age: number }; type C = A & B; // C类型同时有name和age属性。

    • 注意:交叉类型不能交叉矛盾的原始类型(如string & number,结果为never,因为一个值不能同时是string和number)。

    • 典型用法:合并接口、扩展对象类型(如组件 props 的合并)。

2. 接口(Interface)

  • 定义:接口是TS中用于约束对象、函数、类的结构,只定义“结构”,不定义“实现”,核心作用是类型约束和代码复用。

  • 核心用法(对象接口):

    • 基础定义:interface Person { name: string; age: number; }

    • 可选属性(?):接口中某些属性可以不存在(格式:属性名?: 类型),示例:interface Person { name: string; age?: number; }

    • 只读属性(readonly):接口中某些属性只能读取,不能修改(格式:readonly 属性名: 类型),示例:interface Person { readonly id: number; name: string; }

    • 任意属性([key: 类型]: 类型):允许接口有任意额外的属性,示例:interface Person { name: string; [key: string]: any; }

  • 函数接口:约束函数的参数和返回值类型。

    • 示例:interface AddFn { (a: number, b: number): number; }

    • 应用:定义回调函数类型(如axios请求的回调、数组的forEach回调)。

  • 接口的继承(extends):

    • 定义:一个接口可以继承另一个或多个接口,继承父接口的所有属性和方法,还可以扩展自己的属性。

    • 示例:interface Student extends Person { grade: number; } // Student继承Person的name和age,新增grade属性。

    • 多继承:interface A extends B, C { ... } // 继承B和C的所有属性。

  • 接口与类型别名(type)的区别(要点对照):

    • 相同点:都可以定义自定义类型,约束结构。

    • 不同点:

      • interface:只能定义对象/函数/类的结构,支持继承、合并(多个同名interface会自动合并)。

      • type:可以定义任意类型(包括原始类型、联合类型、交叉类型等),不支持继承和合并,支持typeof、keyof等操作。

    • 选用建议:对象与函数结构优先 interface;联合、交叉、映射等用 type 更自然。

3. 泛型(Generic)

  • 定义:泛型是一种“类型参数化”的技术,允许在定义函数、接口、类时,不指定具体类型,而是在使用时传入具体类型,核心价值是“代码复用”和“类型安全”。

  • 核心用法(函数泛型,最常用):

    • 基础定义:function getValue<T>(value: T): T { return value; }

    • 使用方式:

      • 显式指定类型:getValue<string>('张三');

      • 隐式推断类型:getValue(10); // TS推断T为number。

    • 典型用法:封装通用工具函数(如数组处理、请求封装),避免为每种具体类型各写一套签名。

  • 泛型接口:

    • 示例:interface Result<T> { code: number; data: T; } // T为泛型,可传入任意类型(如Result<User>、Result<string[]>)。

    • 应用:接口返回数据的统一格式(如后端接口返回的code和data,data类型不固定)。

  • 泛型类(延伸):

    • 示例:class Stack<T> { private arr: T[] = []; push(item: T) { this.arr.push(item); } pop(): T | undefined { return this.arr.pop(); } }

    • 应用:封装通用类(如栈、队列),支持不同类型的数据。

  • 泛型约束(extends):

    • 定义:限制泛型的取值范围,确保泛型具备某些属性/方法(格式:<T extends 约束类型>)。

    • 示例:function getLength<T extends { length: number }>(value: T): number { return value.length; }

    • 应用:避免泛型传入不满足需求的类型(如上述函数,确保传入的value有length属性)。

  • 泛型默认值:为泛型指定默认类型,未显式传入时使用默认值(格式:<T = 默认类型>)。

4. 类型工具

  • TS 内置类型工具(常用映射与推导):

    • Partial<T>:将T类型的所有属性变为可选属性(如Partial<Person>,Person的所有属性都变为可选)。

    • Required<T>:将T类型的所有可选属性变为必填属性(与Partial相反)。

    • Readonly<T>:将T类型的所有属性变为只读属性。

    • Pick<T, K>:从T类型中挑选出K(指定属性名)对应的属性,组成新类型(如Pick<Person, 'name' | 'age'>)。

    • Omit<T, K>:从T类型中排除K对应的属性,组成新类型(与Pick相反)。

    • Exclude<T, U>:从T类型中排除掉与U类型相同的类型,返回剩余类型(用于联合类型)。

    • Extract<T, U>:从T类型中提取出与U类型相同的类型,返回新类型(与Exclude相反)。

    • ReturnType<T>:获取函数T的返回值类型(如ReturnType<() => string> 结果为string)。

    • Parameters<T>:获取函数T的参数类型,返回一个数组类型(如Parameters<(a: number, b: string) => void> 结果为[number, string])。

  • 自定义类型工具:在 Partial、Pick 等之上组合出贴合业务的类型,示例:

    • // 自定义:排除对象中的null和undefined类型 type NonNullableObj<T> = { [K in keyof T]: NonNullable<T[K]> };

5. 索引类型

  • 索引签名(Index Signature):用于约束对象的“索引”和“值”的类型,分为字符串索引和数字索引。

    • 字符串索引:interface Obj { [key: string]: number; } // 所有字符串索引的属性值都是number类型。

    • 数字索引:interface Arr { [index: number]: string; } // 所有数字索引的属性值都是string类型(类似数组)。

  • keyof 操作符:取出类型的全部属性名,得到字面量联合(如 keyof Person 为 'name' | 'age')。

    • 典型用法:配合泛型安全地按键取值、遍历对象键、约束第二个参数必须是对象的键。

    • 示例:function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }

  • 索引访问类型(T[K]):通过索引获取类型中的属性类型(如Person['name'] 结果为string)。

三、TS 实战应用(结合前端业务)

1. 类与 TS 结合(ES6+TS)

  • 类的类型注解:

    • 属性注解:为类的实例属性指定类型(如class Person { name: string; age: number; })。

    • 构造函数注解:为构造函数的参数指定类型,可通过参数属性简化代码(如constructor(public name: string, public age: number) {})。

    • 方法注解:为类的方法参数和返回值指定类型(如getInfo(): string { return `${this.name}, ${this.age}`; })。

  • 类的访问修饰符:

    • public(默认):类的内部、外部、子类都可以访问。

    • private:只有类的内部可以访问,外部和子类无法访问(私有属性,避免外部修改)。

    • protected:类的内部和子类可以访问,外部无法访问(保护属性,用于子类继承)。

    • readonly:类的属性只能读取,不能修改(可与访问修饰符结合,如private readonly id: number)。

  • 类的继承与多态:

    • 继承:通过extends继承父类,子类可以继承父类的属性和方法,还可以重写父类方法。

    • 多态:子类重写父类方法,不同子类的实例调用同一方法,表现出不同的行为(结合泛型或接口实现)。

  • 抽象类(abstract):

    • 定义:用abstract修饰的类,不能直接实例化,只能被继承,用于定义基类(抽象模板)。

    • 抽象方法:用abstract修饰的方法,只有方法签名,没有实现,子类必须重写该方法。

    • 示例:abstract class Animal { abstract speak(): void; } class Dog extends Animal { speak() { console.log('汪汪'); } }

  • 类实现接口(implements):

    • 定义:类通过implements实现接口,必须实现接口中所有的抽象方法和属性(约束类的结构)。

    • 示例:interface Speak { speak(): void; } class Cat implements Speak { speak() { console.log('喵喵'); } }

    • 多接口实现:class Dog implements Speak, Run { ... } // 实现多个接口,需满足所有接口的约束。

2. 枚举(Enum)

  • 定义:枚举是TS中用于定义“一组有名字的常量”的类型,使代码更具可读性和可维护性(替代魔法数字/字符串)。

  • 核心形态(两种):

    • 数字枚举(默认):枚举值默认是数字,从0开始递增,也可以手动指定值。

      • 示例:enum Direction { Up, Down, Left, Right } // Up=0, Down=1, Left=2, Right=3;手动指定:enum Direction { Up=1, Down=2 }
    • 字符串枚举:成员均为字符串字面量,须逐个指定取值,可读性好,也便于与接口字段对齐。

      • 示例:enum Status { Success = 'success', Fail = 'fail', Pending = 'pending' }
  • 常见用途:

    • 状态与流程(如请求状态、组件内部阶段)。

    • 选项列表(如下拉框选项、按钮类型)。

    • 避免硬编码(如用Status.Success替代'success',减少拼写错误)。

  • 注意事项:枚举会被编译为JS代码(对象),如果不需要编译后的代码,可使用const enum(常量枚举),编译后不会生成额外代码,更高效。

3. 类型断言(Type Assertion)

  • 定义:类型断言是“手动告诉TS某个变量的具体类型”,用于解决TS类型推断不准确的问题(不改变变量的实际类型,只改变TS的类型判断)。

  • 两种写法:

    • as语法(推荐,TSX语法中只能用as):const value = (data as string).length;

    • 尖括号语法:const value = (<string>data).length;

  • 常见使用场景:

    • 接口返回数据类型断言(如后端返回的数据,TS无法推断具体类型,手动断言为自定义接口类型)。

    • 联合类型收窄(如将unknown类型断言为具体类型,访问其属性)。

    • DOM元素类型断言(如const btn = document.getElementById('btn') as HTMLButtonElement;)。

  • 注意事项:类型断言不能“凭空断言”(如不能将string类型断言为number类型),否则会导致类型安全问题,需确保断言的类型是变量的实际类型的子集。

4. TS 配置文件(tsconfig.json)

  • 核心作用:配置TS的编译选项,控制TS的编译行为(如编译目标、模块系统、类型检查严格程度等)。

  • 常用配置项:

    • target:指定编译后的JS版本(如ES5、ES6、ESNext,默认ES3)。

    • module:指定模块系统(如CommonJS、ESModule、UMD,默认CommonJS)。

    • strict:开启严格模式(核心,推荐开启),包含以下子配置:

      • strictNullChecks:开启null和undefined的严格检查(避免null/undefined赋值给非可选类型)。

      • strictFunctionTypes:开启函数参数的严格类型检查。

      • strictPropertyInitialization:确保类的属性在构造函数中初始化。

    • outDir:指定编译后的JS文件输出目录(如dist)。

    • rootDir:指定TS源码目录(如src)。

    • moduleResolution:指定模块解析方式(如Node、Classic,默认Node)。

    • esModuleInterop:解决CommonJS和ESModule的兼容性问题(推荐开启,避免导入模块时的语法问题)。

    • skipLibCheck:跳过第三方库的类型检查(提升编译速度)。

    • declaration:生成.d.ts类型声明文件(用于第三方库或组件库的类型导出)。

  • 前端工程常见组合:开启 strict、esModuleInterop;target 常设为 ESNext;module 常设为 ESModule。

5. TS 与前端框架结合

  • TS 与 Vue 结合(Vue3+TS):

    • 组件props类型约束:通过interface定义props类型,配合defineProps使用。

      • 示例:interface Props { name: string; age?: number; } const props = defineProps<Props>();
    • 组件emit类型约束:通过defineEmits定义emit的事件类型(如defineEmits<{ (e: 'change', value: string): void }>())。

    • ref/reactive类型约束:ref可通过泛型指定类型(如const count = ref<number>(0)),reactive可通过interface约束对象类型。

    • 组合式API类型:setup函数的返回值类型、自定义hooks的类型约束。

  • TS 与 React 结合(React+TS):

    • 函数组件类型:通过FC(FunctionComponent)定义组件类型,约束props和children。

      • 示例:interface Props { name: string; } const MyComponent: React.FC<Props> = ({ name, children }) => { ... }
    • Hooks类型约束:

      • useState:通过泛型指定状态类型(如const [count, setCount] = useState<number>(0))。

      • useEffect:无返回值或返回清理函数,无需额外类型注解。

      • useRef:通过泛型指定ref的类型(如const inputRef = useRef<HTMLInputElement>(null))。

    • 事件类型:如onClick事件类型为React.MouseEvent<HTMLButtonElement>。

四、TS 高级进阶

1. 类型收窄(Type Narrowing)

  • 定义:将联合类型、unknown类型等“宽泛类型”缩小为“具体类型”,从而访问该类型的专属属性和方法,避免类型错误。

  • 常用收窄手段:

    • typeof类型守卫:通过typeof判断变量的原始类型(如typeof value === 'string')。

    • instanceof类型守卫:通过instanceof判断变量的引用类型(如value instanceof Array)。

    • in类型守卫:通过in判断对象是否包含某个属性(如'name' in value)。

    • 字面量类型收窄:通过判断变量是否等于某个字面量(如if (status === 'success'))。

    • 自定义类型守卫:函数返回值写成类型谓词 value is SomeType,在 if 分支内帮助编译器收窄(如 function isPerson(value: unknown): value is Person { ... })。

2. 字面量类型(Literal Types)

  • 定义:字面量类型是“具体的值”作为类型,如'success'、10、true等,用于约束变量只能取某个具体的值。

  • 常见形态:

    • 字符串字面量:type Status = 'success' | 'fail' | 'pending'; // 变量只能是这三个值中的一个。

    • 数字字面量:type Size = 10 | 20 | 30; // 变量只能是这三个数字中的一个。

    • 布尔字面量:type Bool = true | false;(较少用,等同于boolean)。

  • 典型用法:收窄函数参数、组件 props、配置项的合法取值,在类型层挡住非法字面量。

3. 装饰器(Decorator)

  • 定义:装饰器是一种特殊的声明,用于修饰类、类的属性、方法、参数,可在不修改原代码的情况下,为其添加额外功能(如日志、权限校验)。

  • 常见分类:

    • 类装饰器:修饰整个类,接收类作为参数,可修改类的原型或构造函数。

    • 方法装饰器:修饰类的方法,接收类的原型、方法名、方法描述符作为参数,可修改方法的行为(如拦截方法调用)。

    • 属性装饰器:修饰类的属性,接收类的原型、属性名作为参数,可修改属性的取值和赋值行为。

  • 注意事项:装饰器目前是TS的实验性特性,需在tsconfig.json中开启experimentalDecorators: true才能使用,常见于Vue3、NestJS等框架。

4. 声明文件(.d.ts)

  • 定义:声明文件(.d.ts)用于“描述已存在的JS代码的类型”,为没有类型注解的JS库(如第三方库)提供类型支持,让TS能够识别其类型。

  • 核心作用:

    • 为第三方JS库添加类型(如jQuery、lodash等,通过@types/xxx安装声明文件)。

    • 声明全局变量、全局函数(如window上的全局变量)。

    • 拆分类型声明,提升代码可维护性(如将接口、类型别名单独放在.d.ts文件中)。

  • 常用声明语法:

    • 声明模块:declare module 'xxx' { ... }(为第三方模块声明类型)。

    • 声明全局:declare global { ... }(声明全局变量/函数)。

    • 声明接口/类型:declare interface Person { ... }(全局接口)。

5. 泛型工具高级应用

  • 泛型条件类型(Conditional Types):通过条件判断动态生成类型(格式:T extends U ? X : Y)。

    • 示例:type IsString<T> = T extends string ? true : false; // IsString<string> = true,IsString<number> = false。
  • 泛型工具嵌套使用:结合多个内置泛型工具,封装复杂类型(如type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;,深度可选类型)。