19-TypeScript 基础集成

发布时间:2026/6/25 18:57:44
19-TypeScript 基础集成 TypeScript 基础集成从 JavaScript 到 TypeScript用静态类型提升代码质量与开发体验学习目标读完本文你将学会理解 TypeScript 的类型系统和编译原理掌握常用类型注解和接口定义使用泛型编写可复用的类型安全代码在现有 JavaScript 项目中渐进式引入 TypeScript一、为什么要用 TypeScript1.1 JavaScript 的类型问题// 运行时才发现错误functionadd(a,b){returnab;}add(1,2);// 3 ✅add(1,2);// 12 ❌ 逻辑错误但语法合法add(1,2);// 12 ❌ 更隐蔽的问题// 属性拼写错误constuser{name:Alice};console.log(user.nmae);// undefined不报错1.2 TypeScript 的价值JavaScript TypeScript ↓ ↓ 动态类型 静态类型检查 运行时错误 编译时捕获错误 IDE 提示弱 智能补全和重构 文档靠注释 类型即文档 重构风险高 安全重构1.3 TS 编译流程TypeScript 源码 ↓ tsc 编译器 ↓ 类型检查 语法转换 ↓ JavaScript 目标代码ES5/ES6/ESNext ↓ 浏览器 / Node.js 运行二、基础类型2.1 基本类型注解// 原始类型letname:stringAlice;letage:number25;letisActive:booleantrue;letempty:nullnull;letnotDefined:undefinedundefined;// 任意类型尽量少用letanything:any4;anythingstring;anythingtrue;// 未知类型类型安全的 anyletunknownValue:unknown4;// unknownValue.toFixed(); // ❌ 错误先需要类型断言或类型守卫if(typeofunknownValuenumber){unknownValue.toFixed();// ✅}// 无返回值functionlogMessage(msg:string):void{console.log(msg);}// 永不返回functionthrowError(msg:string):never{thrownewError(msg);}2.2 数组与元组// 数组letnumbers:number[][1,2,3];letnames:Arraystring[Alice,Bob];// 元组固定长度和类型letpoint:[number,number][10,20];letuserInfo:[string,number,boolean][Alice,25,true];// 只读数组constreadonlyArr:readonlynumber[][1,2,3];// readonlyArr.push(4); // ❌ 错误2.3 对象与接口// 接口定义interfaceUser{id:number;name:string;email:string;age?:number;// 可选属性readonlycreatedAt:Date;// 只读属性}constuser:User{id:1,name:Alice,email:aliceexample.com,createdAt:newDate()};// 索引签名interfaceDictionary{[key:string]:string;}constcolors:Dictionary{red:#ff0000,green:#00ff00};// 类型别名typePoint{x:number;y:number};typeIDstring|number;typeCallback(data:string)void;三、联合类型与类型守卫3.1 联合类型functionformatInput(input:string|number):string{// 类型守卫if(typeofinputstring){returninput.trim();// TS 知道这里是 string}returninput.toFixed(2);// TS 知道这里是 number}3.2 类型收窄interfaceBird{type:bird;fly():void;}interfaceFish{type:fish;swim():void;}typeAnimalBird|Fish;functionmove(animal:Animal){// 可辨识联合switch(animal.type){casebird:animal.fly();// TS 知道是 Birdbreak;casefish:animal.swim();// TS 知道是 Fishbreak;default:const_exhaustive:neveranimal;// 穷尽检查}}四、泛型4.1 基础泛型// 泛型函数functionidentityT(value:T):T{returnvalue;}constnumidentitynumber(42);// numberconststridentity(hello);// 类型推断为 string// 泛型接口interfaceContainerT{value:T;getValue():T;}constnumberBox:Containernumber{value:100,getValue(){returnthis.value;}};4.2 泛型约束interfaceHasLength{length:number;}functionlogLengthTextendsHasLength(arg:T):T{console.log(arg.length);returnarg;}logLength(hello);// ✅ string 有 lengthlogLength([1,2,3]);// ✅ 数组有 length// logLength(123); // ❌ number 没有 length4.3 泛型工具类型// Partial: 所有属性可选interfaceUser{id:number;name:string;}typePartialUserPartialUser;// { id?: number; name?: string; }// Pick: 选取部分属性typeUserNamePickUser,name;// { name: string; }// Omit: 排除部分属性typeUserWithoutIdOmitUser,id;// { name: string; }// Record: 键值对对象typePageInfoRecordstring,{title:string;path:string};// ReturnType: 提取函数返回类型functioncreateUser(){return{id:1,name:Alice};}typeNewUserReturnTypetypeofcreateUser;// Parameters: 提取函数参数类型typeCreateUserParamsParameterstypeofcreateUser;五、类与面向对象interfaceAnimal{name:string;makeSound():void;}classDogimplementsAnimal{name:string;privateage:number;// 私有属性protectedbreed:string;// 受保护属性constructor(name:string,age:number,breed:string){this.namename;this.ageage;this.breedbreed;}makeSound():void{console.log(${this.name}says: Woof!);}// GettergetisAdult():boolean{returnthis.age2;}// 静态方法staticcreatePuppy(name:string):Dog{returnnewDog(name,0,Unknown);}}constdognewDog(Buddy,3,Golden Retriever);dog.makeSound();console.log(dog.isAdult);// true// console.log(dog.age); // ❌ 私有属性不可访问六、在 JS 项目中渐进式引入 TS6.1 步骤# 1. 安装 TypeScriptnpminstall--save-dev typescript# 2. 初始化配置npx tsc--init# 3. 重命名文件 .js → .ts或保留 .js添加 JSDoc 类型注释# 4. 配置 tsconfig.json// tsconfig.json{compilerOptions:{target:ES2020,module:ESNext,moduleResolution:node,strict:true,esModuleInterop:true,skipLibCheck:true,forceConsistentCasingInFileNames:true,outDir:./dist,rootDir:./src,declaration:true,declarationMap:true,sourceMap:true},include:[src/**/*],exclude:[node_modules,dist,**/*.test.ts]}6.2 JSDoc 类型注释不修改 .js 文件/** * param {string} name * param {number} age * returns {string} */functiongreet(name,age){returnHello${name}, you are${age};}/** type {import(./types).User} */constuser{id:1,name:Alice};二、常见误区与注意点误区正确做法TypeScript 在运行时做类型检查TS 类型只在编译时检查运行时无类型信息any 可以随便用尽量不用 any使用 unknown 类型守卫接口和类型别名完全等价接口可声明合并类型别名更灵活泛型越复杂越好泛型应服务于复用避免过度抽象一次性全量迁移到 TS渐进式迁移从核心模块开始三、动手练习练习 1为 API 响应定义类型为一组 REST API 接口定义请求参数和响应数据的 TypeScript 类型。练习 2实现泛型工具函数实现一个deepClone泛型函数支持深拷贝任意对象。四、AI 辅助学习4.1 本节知识点的 AI 提问模板“TypeScript 的 interface 和 type 有什么区别”“如何实现一个类型安全的 EventEmitter”“unknown 和 any 的区别是什么”4.2 警惕 AI 的常见错误AI 可能生成运行时依赖类型信息的代码如typeof variable UserAI 可能忘记 TS 类型擦除特性五、配套代码本文示例代码位于CODE-ADVANCED/19-TypeScript基础集成/文件名说明ts-basic.ts基础类型、接口、类型守卫ts-advanced.ts泛型、工具类型、类与面向对象ts-config-demo.jsontsconfig.json 推荐配置六、本章小结TypeScript 在编译时进行类型检查捕获潜在错误接口、类型别名、联合类型构建类型系统基础泛型让代码在保证类型安全的同时保持复用性现有 JS 项目可通过渐进式迁移引入 TS如果本文对你有帮助欢迎点赞、收藏、关注专栏。有任何问题可以在评论区交流