简述网站内容如何优化注册微信号的网站

张小明 2025/12/28 19:41:22
简述网站内容如何优化,注册微信号的网站,做公司网站需要多久,wordpress 自建网站TypeScript#xff08;简称 TS#xff09;是 JavaScript 的强类型超集#xff0c;在 JS 基础上增加了静态类型系统#xff0c;可编译为纯 JS 运行于任何支持 JS 的环境。核心价值是类型校验#xff08;提前发现错误#xff09;、代码提示#xff08;提升开发效率#x…TypeScript简称 TS是 JavaScript 的强类型超集在 JS 基础上增加了静态类型系统可编译为纯 JS 运行于任何支持 JS 的环境。核心价值是类型校验提前发现错误、代码提示提升开发效率、工程化支撑适配大型项目目前已成为 Vue3、React、Node.js 等生态的主流开发语言。一、TypeScript 基础入门1. 环境搭建与编译1.1 安装 TS通过 npm/yarn 全局安装 TypeScript 编译器tsc# npm 安装npminstalltypescript -g# yarn 安装yarnglobaladdtypescript1.2 初始化 TS 配置在项目根目录执行tsc --init生成默认配置文件tsconfig.json核心配置后续详解关键默认配置{compilerOptions:{target:ES2016,// 编译后 JS 版本ES3/ES5/ES6module:CommonJS,// 模块规范CommonJS/ESNext/AMDoutDir:./dist,// 编译后 JS 文件输出目录rootDir:./src,// TS 源码目录strict:true,// 开启严格模式强烈推荐强制类型校验esModuleInterop:true// 兼容 CommonJS 和 ESM 模块},include:[./src/**/*],// 需要编译的 TS 文件exclude:[node_modules]// 排除的目录}1.3 编译运行 TS新建src/index.tsTS 源码文件编写代码后执行编译tsc# 执行编译按 tsconfig.json 配置编译所有 TS 文件tsc src/index.ts# 单独编译指定 TS 文件tsc --watch# 监听 TS 文件变化自动重新编译开发必备编译后会在dist目录生成对应index.js直接运行 JS 文件即可node dist/index.js2. 核心基础类型最常用必须掌握TS 提供 10 基础类型覆盖 JS 原生类型 新增类型变量声明时需指定类型或让 TS 自动推导赋值时类型必须匹配否则编译报错。2.1 基本原生类型对应 JS 原生类型类型说明示例代码string字符串类型let name: string 张三; const msg: string Hello ${name};number数字类型整数/浮点数let age: number 25; const pi: number 3.14; const hex: number 0x10;boolean布尔类型let isDone: boolean true; const isLoading: boolean false;null空值类型let n: null null;undefined未定义类型let u: undefined undefined;symbol唯一值类型ES6const id: symbol Symbol(id); const id2: symbol Symbol(id);id≠id2bigint大整数类型ES11let bigNum: bigint 100n; const max: bigint 9007199254740991n;2.2 TS 新增基础类型类型说明示例代码any任意类型关闭类型校验尽量少用let val: any 123; val abc; val true;无类型报错unknown未知类型安全版 any需先校验类型才能使用let unk: unknown hello; if (typeof unk string) { console.log(unk.length); }void无返回值类型常用于函数返回值function log(): void { console.log(日志); }函数无 return 或 return undefinednever永无返回值类型函数永远不会执行完如抛出错误、无限循环function throwErr(): never { throw new Error(报错); } function loop(): never { while(true) {} }2.3 类型推导TS 自动识别类型简化代码若变量声明时直接赋值TS 会自动推导变量类型无需手动指定推荐优先用类型推导减少冗余// 自动推导为 string 类型letname李四;// name 123; // 报错类型 number 不能赋值给类型 string// 自动推导为 number 类型letage30;// 函数返回值自动推导为 number 类型functionadd(a:number,b:number){returnab;}3. 数组类型3 种声明方式数组元素类型需统一TS 提供 3 种简洁的声明方式优先用前两种// 方式 1类型 []最常用letarr1:number[][1,2,3];// 数字数组letarr2:string[][a,b,c];// 字符串数组// arr1.push(4); // 报错不能将类型 string 分配给类型 number// 方式 2Array类型泛型写法后续详解泛型letarr3:Arrayboolean[true,false];// 布尔数组letarr4:Arraynumber[4,5,6];// 方式 3联合类型数组数组元素可多种类型后续详解联合类型letarr5:(number|string)[][1,a,2,b];// 数字或字符串数组4. 元组类型Tuple固定长度固定类型的数组元组是特殊的数组需明确指定「每个位置的元素类型」和「数组长度」赋值时类型、顺序、长度必须完全匹配常用于多返回值场景// 声明元组第一个元素 string第二个 number第三个 booleanlettuple:[string,number,boolean][张三,25,true];// 正确取值类型自动推导letnametuple[0];// string 类型letagetuple[1];// number 类型// 错误用法编译报错// tuple [李四, 30, true]; // 第二个元素应为 number实际是 string// tuple [李四, 30]; // 长度应为 3实际是 2// tuple.push(额外元素); // 严格模式下报错非严格模式允许不推荐// 实战场景函数返回多类型值functiongetUserInfo():[string,number]{return[张三,25];}const[userName,userAge]getUserInfo();// 解构赋值类型自动匹配二、TypeScript 进阶类型项目核心进阶类型是 TS 工程化能力的核心覆盖「复杂数据结构描述」「类型复用」「类型约束」等场景掌握后可应对 90% 项目需求。1. 联合类型Union Type|连接多个类型表示变量/参数可以是「多个类型中的任意一种」使用时需通过「类型守卫」判断类型避免报错// 1. 基础用法变量可以是 number 或 string 类型letunionVal:number|string;unionVal123;// 合法unionValabc;// 合法// unionVal true; // 报错类型 boolean 不在联合类型中// 2. 函数参数联合类型常用场景functionformatValue(val:number|string):string{// 类型守卫判断 val 是 string 类型避免调用 length 时报错if(typeofvalstring){returnval.toUpperCase();// 此时 TS 确定 val 是 string可调用 string 方法}// 否则 val 是 number 类型returnval.toFixed(2);// 调用 number 方法}console.log(formatValue(3.1415));// 3.14console.log(formatValue(hello));// HELLO// 3. 联合类型 字面量类型精准约束取值范围常用typeStatussuccess|error|loading;// 字面量联合类型后续详解 typeletrequestStatus:Status;requestStatussuccess;// 合法requestStatuserror;// 合法// requestStatus pending; // 报错不在 Status 类型范围内2. 交叉类型Intersection Type合并多个类型表示将「多个类型的属性/方法合并为一个新类型」新类型包含所有原类型的成员常用于对象类型合并// 1. 基础用法合并两个对象类型typePerson{name:string;age:number};typeJob{job:string;salary:number};// 交叉类型同时拥有 Person 和 Job 的所有属性typePersonWithJobPersonJob;// 赋值时必须包含所有属性constperson:PersonWithJob{name:张三,age:25,job:前端开发,salary:20000};// 2. 函数参数交叉类型合并多个参数类型约束typeBaseParams{id:number};typePageParams{page:number;size:number};functionfetchData(params:BaseParamsPageParams){console.log(params.id,params.page,params.size);}fetchData({id:1,page:1,size:10});// 合法// 3. 注意基本类型交叉无意义会变成 never 类型typeNeverTypenumberstring;// never 类型无任何值能同时是 number 和 string3. 类型别名Type Aliastype关键字复用类型用type给「任意类型」起别名简化复杂类型的使用支持复用和组合核心作用类型复用// 1. 基础类型别名简化重复类型typeStrTypestring;typeNumTypenumber;letstr:StrTypehello;letnum:NumType123;// 2. 复杂类型别名常用场景联合类型、对象类型、元组类型// 联合类型别名约束状态值typeStatussuccess|error|loading;// 对象类型别名描述用户数据结构typeUser{id:number;name:string;age?:number;// 可选属性后续详解readonlyphone:string;// 只读属性后续详解};// 元组类型别名描述坐标typePoint[number,number];// 3. 类型别名组合复用已有类型typeUserWithAddressUser{address:string};// 交叉合并constuser:UserWithAddress{id:1,name:张三,phone:13800138000,address:北京市};// 4. 函数类型别名描述函数结构后续详解函数类型typeFnType(a:number,b:number)number;constadd:FnType(x,y)xy;4. 接口Interfaceinterface关键字描述对象/类结构interface主要用于「描述对象的属性结构」或「类的抽象结构」功能与type类似但更侧重「结构约束」支持「继承」和「扩展」// 1. 基础用法描述对象结构与 type 类似interfacePerson{name:string;// 必选属性age?:number;// 可选属性? 表示可填可不填readonlyid:number;// 只读属性初始化后不能修改[key:string]:any;// 任意属性允许添加未定义的属性key 为 string 类型值为 any 类型}// 赋值时必选属性必须填可选属性可省略任意属性可额外添加constp1:Person{id:1,name:张三,// age: 25, // 可选可省略gender:男// 任意属性合法};// p1.id 2; // 报错只读属性不能修改p1.age26;// 可选属性可修改// 2. 接口继承核心优势复用已有接口扩展新属性interfaceStudentextendsPerson{studentId:number;// 新增学生专属属性study():void;// 新增学生专属方法无返回值}// 赋值时需包含 Person Student 的所有属性/方法conststudent:Student{id:2,name:李四,studentId:1001,study(){console.log(学习 TypeScript);}};// 3. 接口扩展合并多个接口与交叉类型类似interfaceA{a:number}interfaceB{b:string}interfaceCextendsA,B{c:boolean}// 继承 A 和 Bconstobj:C{a:1,b:2,c:true};// 4. 接口描述函数类型与 type 类似少用优先用 typeinterfaceFnInterface{(a:number,b:number):number;}constmultiply:FnInterface(x,y)x*y;5.typevsinterface关键区别避免混淆两者功能高度重合都能描述对象/函数类型但有核心区别项目中需合理选择对比维度type类型别名interface接口核心用途给任意类型起别名基础类型、联合、交叉等描述对象/类的结构侧重「结构约束」继承能力无直接继承需用交叉类型实现合并支持extends继承结构更清晰合并能力不支持重复定义合并重复定义会报错支持重复定义合并多个同名接口自动合并属性支持类型支持所有类型基础、联合、交叉、元组等主要支持对象/类/函数类型不支持基础类型别名实战选择1. 基础类型/联合/交叉/元组的别名2. 函数类型1. 对象结构描述2. 类的抽象结构继承场景实战示例重复定义合并interface 独有// interface 重复定义自动合并属性interfaceUser{id:number;name:string}interfaceUser{age?:number;gender:string}// 最终 User 接口{ id: number; name: string; age?: number; gender: string }constuser:User{id:1,name:张三,gender:男};// type 重复定义直接报错typeUserType{id:number};// type UserType { name: string }; // 报错标识符 UserType 重复6. 函数类型约束函数的参数和返回值TS 对函数的约束包括「参数类型」「参数个数」「返回值类型」支持「可选参数」「默认参数」「剩余参数」等场景6.1 基础函数类型声明// 方式 1直接声明最常用// 参数 a/b 为 number 类型返回值为 number 类型返回值可省略TS 自动推导functionadd(a:number,b:number):number{returnab;}// 方式 2类型别名声明复用函数类型typeFn(x:number,y:number)number;constsubtract:Fn(x,y)x-y;// 方式 3接口声明少用优先用 typeinterfaceMultiplyFn{(x:number,y:number):number;}constmultiply:MultiplyFn(x,y)x*y;6.2 可选参数与默认参数可选参数用?标记必须放在「必选参数后面」默认参数参数赋值默认值TS 会自动推导类型默认参数可放在必选参数前面但调用时需显式传undefined跳过// 1. 可选参数age 可选放在必选参数 name 后面functiongetUser(name:string,age?:number):string{returnage?${name},${age}岁:name;}getUser(张三);// 合法省略可选参数getUser(张三,25);// 合法// 2. 默认参数age 有默认值类型自动推导为 numberfunctiongreet(name:string,age:number18):string{returnHello${name},${age}岁;}greet(李四);// 合法使用默认值 18greet(李四,30);// 合法覆盖默认值// 3. 默认参数在前需显式传 undefined 跳过functionfn(a:number10,b:number):number{returnab;}fn(undefined,20);// 合法a 用默认值 10b 传 206.3 剩余参数...接收多个参数转为数组剩余参数必须是「最后一个参数」类型需声明为数组类型// 剩余参数 nums 为 number 数组返回所有数字的和functionsum(...nums:number[]):number{returnnums.reduce((total,num)totalnum,0);}console.log(sum(1,2,3));// 6console.log(sum(4,5,6,7));// 22// 剩余参数 固定参数functionlogInfo(name:string,...details:string[]):void{console.log(姓名${name}详情${details.join(, )});}logInfo(张三,25岁,前端开发);// 姓名张三详情25岁, 前端开发6.4 无返回值函数void类型函数无return或return undefined时返回值类型为void可省略TS 自动推导// 显式声明 voidfunctionlogMsg(msg:string):void{console.log(msg);// return; // 合法无返回值// return undefined; // 合法返回 undefinedvoid 允许// return 123; // 报错不能返回 number 类型}// 省略返回值类型TS 自动推导为 voidfunctionalertMsg(msg:string){alert(msg);}7. 泛型GenericT类型复用动态类型约束泛型是 TS 最强大的特性之一核心作用是「让类型可复用、可动态传递」解决「重复定义相似类型」和「类型与值关联」的问题比如数组、函数、组件的通用类型约束。7.1 泛型基础函数泛型最常用场景需求编写一个「返回传入值本身」的函数支持任意类型number/string/对象等且返回值类型与传入值一致。// 1. 泛型函数定义T 是泛型参数T 是占位符可自定义名称如 K U// T 会动态接收传入参数的类型参数 val 类型为 T返回值类型也为 TfunctionidentityT(val:T):T{returnval;}// 2. 调用泛型函数2 种方式// 方式 1显式指定泛型类型number 表示 Tnumberconstnumidentitynumber(123);// num 类型为 number// 方式 2TS 自动推导泛型类型推荐简化代码conststridentity(abc);// 自动推导 Tstringstr 类型为 stringconstobjidentity({name:张三});// 自动推导 T对象类型// 3. 多泛型参数多个动态类型传递// T 表示第一个参数类型U 表示第二个参数类型返回值为 [T, U] 元组类型functionmergeT,U(a:T,b:U):[T,U]{return[a,b];}// 自动推导 TnumberUstring返回值类型为 [number, string]constmergedmerge(123,abc);const[numVal,strVal]merged;// numVal: numberstrVal: string7.2 泛型约束extends限制泛型的范围泛型默认支持任意类型若需「约束泛型必须包含某个属性/方法」需用extends实现泛型约束// 需求函数接收一个对象返回对象的 length 属性需确保对象有 length 属性interfaceHasLength{length:number;// 约束泛型必须有 length 属性}// 泛型约束T extends HasLength → T 必须是 HasLength 的子类型包含 length 属性functiongetLengthTextendsHasLength(val:T):number{returnval.length;}// 合法调用传入值有 length 属性getLength(abc);// 字符串有 length返回 3getLength([1,2,3]);// 数组有 length返回 3getLength({length:5});// 对象有 length返回 5// 报错传入值无 length 属性// getLength(123); // number 类型无 length 属性// getLength(true); // boolean 类型无 length 属性7.3 泛型接口/类型别名复用泛型对象类型用泛型定义接口/类型别名实现「通用对象类型复用」// 1. 泛型类型别名描述通用数组/对象// 通用数组类型等价于 T[]typeGenericArrayTArrayT;constnumArr:GenericArraynumber[1,2,3];// 数字数组conststrArr:GenericArraystring[a,b,c];// 字符串数组// 通用对象类型键为 string值为 T 类型typeGenericObjT{[key:string]:T};constobj1:GenericObjnumber{a:1,b:2};// 值为 numberconstobj2:GenericObjstring{name:张三,age:25};// 值为 string// 2. 泛型接口描述通用函数/对象interfaceGenericFnT,U{(param:T):U;// 接收 T 类型参数返回 U 类型值}// 实现泛型接口TnumberUstringconstnumToString:GenericFnnumber,string(num)num.toString();numToString(123);// 返回 123类型为 string7.4 泛型默认值给泛型参数设置默认类型泛型参数可设置默认值若调用时未指定且无法推导则使用默认类型// 泛型默认值T 默认为 string 类型functioncreateArrayTstring(length:number,val:T):T[]{returnArray(length).fill(val);}// 1. 未指定泛型自动推导 Tnumberval 是 number 类型constarr1createArray(3,123);// number[] 类型[123, 123, 123]// 2. 未指定泛型无法推导val 未传不这里 val 必传换个例子// 泛型默认值示例 2T 默认为 numbertypeDefaultGenericTnumber{value:T};constobj1:DefaultGeneric{value:123};// Tnumber使用默认值constobj2:DefaultGenericstring{value:abc};// Tstring指定类型8. 类型守卫Type Guard缩小类型范围类型守卫是「在运行时判断变量类型」的逻辑让 TS 在编译时就能确定变量的具体类型避免联合类型使用时的报错核心通过判断让 TS 识别更精准的类型。8.1 常用类型守卫方式类型守卫方式适用场景示例代码typeof类型守卫基础类型string/number/boolean/symbolif (typeof val string) { /* val 是 string 类型 */ }instanceof类型守卫引用类型数组/对象/类实例if (val instanceof Array) { /* val 是数组类型 */ }in类型守卫对象是否包含某个属性if (age in val) { /* val 包含 age 属性 */ }字面量类型守卫联合字面量类型判断if (status success) { /* status 是 success 类型 */ }自定义类型守卫复杂类型判断自定义逻辑function isUser(val: any): val is User { return id in val name in val; }8.2 实战示例// 1. typeof 类型守卫基础类型判断functionhandleValue(val:number|string|boolean){if(typeofvalstring){console.log(val.length);// val 是 string 类型可调用 length}elseif(typeofvalnumber){console.log(val.toFixed(2));// val 是 number 类型可调用 toFixed}else{console.log(val?true:false);// val 是 boolean 类型}}// 2. instanceof 类型守卫引用类型判断classAnimal{name:string;constructor(name:string){this.namename;}}classDogextendsAnimal{bark(){console.log(汪汪);}}classCatextendsAnimal{meow(){console.log(喵喵);}}functionanimalSound(animal:Animal){if(animalinstanceofDog){animal.bark();// animal 是 Dog 类型可调用 bark 方法}elseif(animalinstanceofCat){animal.meow();// animal 是 Cat 类型可调用 meow 方法}}animalSound(newDog(旺财));// 汪汪// 3. in 类型守卫对象属性判断typeUser{id:number;name:string};typeProduct{id:number;price:number};functiongetInfo(item:User|Product){if(nameinitem){console.log(用户${item.name});// item 是 User 类型}else{console.log(商品价格${item.price});// item 是 Product 类型}}// 4. 自定义类型守卫复杂类型判断// 自定义函数返回值为 val is User类型谓词表示若返回 true则 val 是 User 类型functionisUser(val:any):valisUser{// 判断逻辑val 是对象且包含 id 和 name 属性且 id 是 number 类型returntypeofvalobjectval!nullidinvalnameinvaltypeofval.idnumber;}functionprintUser(val:any){if(isUser(val)){console.log(val.id,val.name);// TS 确定 val 是 User 类型无报错}else{console.log(不是 User 类型);}}printUser({id:1,name:张三});// 1 张三printUser({price:100});// 不是 User 类型9. 索引类型Index Type操作对象的属性名/属性值类型索引类型用于「动态获取对象的属性名类型」或「属性值类型」核心语法keyof T获取对象类型T的所有属性名组成的联合类型索引签名T[K]获取对象类型T中属性名类型为K的属性值类型索引访问9.1 基础用法keyof与T[K]// 定义对象类型typeUser{id:number;name:string;age:number;};// 1. keyof T获取 User 的所有属性名组成的联合类型 → id | name | agetypeUserKeyskeyofUser;constkey1:UserKeysid;// 合法constkey2:UserKeysname;// 合法// const key3: UserKeys gender; // 报错不在属性名联合类型中// 2. T[K]获取属性值类型K 是属性名类型// 获取 User 中 id 属性的类型 → numbertypeIdTypeUser[id];// 获取 User 中 name 属性的类型 → stringtypeNameTypeUser[name];// 获取 User 中多个属性的类型 → number | stringtypeMixedTypeUser[id|name];// 3. 泛型 索引类型实战场景安全获取对象属性// 函数功能获取对象 obj 中 key 对应的属性值确保 key 是 obj 的合法属性functiongetPropT,KextendskeyofT(obj:T,key:K):T[K]{returnobj[key];}constuser:User{id:1,name:张三,age:25};// 合法调用key 是 User 的属性名返回值类型自动匹配constuserIdgetProp(user,id);// number 类型constuserNamegetProp(user,name);// string 类型// 报错key 不是 User 的属性名TS 编译时拦截错误避免运行时 bug// const userGender getProp(user, gender);9.2 索引签名描述任意属性的对象类型当对象属性不固定时用索引签名描述「属性名类型」和「属性值类型」支持两种索引字符串索引[key: string]: 类型属性名是 string 类型数字索引[key: number]: 类型属性名是 number 类型常用于数组// 1. 字符串索引签名属性名是 string属性值是 numbertypeNumObj{[key:string]:number;};constobj1:NumObj{a:1,b:2,c:3};// 合法// const obj2: NumObj { a: 1, b: 2 }; // 报错属性值必须是 number// 2. 混合索引签名固定属性 任意属性typeUser{id:number;// 固定属性类型必须兼容任意属性的类型[key:string]:number|string;// 任意属性值可以是 number 或 string};constuser:User{id:1,// 固定属性number 兼容任意属性类型name:张三,// 任意属性string 类型age:25// 任意属性number 类型};// 3. 数字索引签名常用于数组等价于 T[]typeNumArray{[key:number]:number;};constarr:NumArray[1,2,3];// 合法数组索引是 number 类型值是 number 类型arr[0]4;// 合法// arr[0] 4; // 报错值必须是 number 类型10. 映射类型Mapped Type基于已有类型生成新类型映射类型是「基于已有类型批量修改属性的类型或修饰符」核心语法{ [K in keyof T]: 新类型 }本质是「遍历已有类型的属性生成新类型」TS 内置了多个常用映射类型也支持自定义。10.1 基础自定义映射类型// 原始类型typeUser{id:number;name:string;age:number;};// 1. 基础映射遍历 User 的所有属性属性值类型改为 string批量修改类型typeUserToString{[KinkeyofUser]:string;// K 遍历 keyof Userid | name | age值类型改为 string};// UserToString 等价于{ id: string; name: string; age: string }constuser1:UserToString{id:1,name:张三,age:25};// 2. 映射 泛型通用映射类型复用// 通用映射将任意类型 T 的所有属性值类型改为 UtypeMapTypeT,U{[KinkeyofT]:U;};// 将 User 的所有属性值改为 boolean 类型typeUserToBooleanMapTypeUser,boolean;// 等价于{ id: boolean; name: boolean; age: boolean }// 3. 映射 索引类型基于原始属性值类型修改// 通用映射将任意类型 T 的所有属性值类型改为「原始类型 string」的联合类型typeMapWithOriginalTypeT{[KinkeyofT]:T[K]|string;// T[K] 是原始属性值类型};typeUserWithStringMapWithOriginalTypeUser;// 等价于{ id: number | string; name: string | string; age: number | string }10.2 TS 内置映射类型常用直接复用TS 内置了 6 个常用映射类型覆盖「可选属性」「只读属性」「属性值可选」等场景无需自定义内置映射类型作用基于 T 生成新类型示例基于 User 类型PartialT将 T 的所有属性改为「可选属性」?PartialUser→ { id?: number; name?: string; age?: number }RequiredT将 T 的所有属性改为「必选属性」移除?RequiredPartialUser→ 还原 User 类型ReadonlyT将 T 的所有属性改为「只读属性」readonlyReadonlyUser→ { readonly id: number; … }PickT, K从 T 中「挑选部分属性 K」生成新类型K 是 T 的属性子集PickUser, “id”OmitT, K从 T 中「排除部分属性 K」生成新类型K 是 T 的属性子集OmitUser, age→ { id: number; name: string }RecordK, T生成「属性名为 K 类型属性值为 T 类型」的对象类型通用对象类型Recordstring, number→ { [key: string]: number }10.3 内置映射类型实战示例typeUser{id:number;name:string;age:number;};// 1. PartialT可选属性常用于更新对象时只传部分属性functionupdateUser(user:User,updates:PartialUser):User{return{...user,...updates};// 合并原始用户和更新属性}constoldUser:User{id:1,name:张三,age:25};// 只更新 name 属性其他属性可选constnewUserupdateUser(oldUser,{name:李四});// 2. ReadonlyT只读属性防止对象被修改constreadonlyUser:ReadonlyUser{id:1,name:张三,age:25};// readonlyUser.name 李四; // 报错只读属性不能修改// 3. PickT, K挑选属性获取对象的部分属性typeUserBasicInfoPickUser,id|name;// 只保留 id 和 nameconstbasicInfo:UserBasicInfo{id:1,name:张三};// 4. OmitT, K排除属性剔除对象的部分属性typeUserWithoutAgeOmitUser,age;// 排除 age 属性constuserWithoutAge:UserWithoutAge{id:1,name:张三};// 5. RecordK, T通用对象类型快速创建对象类型常用// 场景 1键为 string值为 User用户列表typeUserListRecordstring,User;constuserList:UserList{1:{id:1,name:张三,age:25},2:{id:2,name:李四,age:30}};// 场景 2键为联合类型值为 string状态描述typeStatussuccess|error|loading;typeStatusDescRecordStatus,string;conststatusDesc:StatusDesc{success:请求成功,error:请求失败,loading:请求中};三、TypeScript 高级特性大型项目必备1. 类与 TypeScript面向对象 类型约束TS 对 ES6 类进行了类型增强支持「属性类型声明」「方法类型声明」「访问修饰符」「抽象类」等让类的结构更清晰类型更安全。1.1 类的基础类型声明classPerson{// 1. 属性类型声明必选TS 要求显式声明属性类型name:string;// 实例属性默认 publicage:number;readonlygender:string;// 只读属性初始化后不能修改// 2. 构造函数初始化属性参数可声明类型constructor(name:string,age:number,gender:string){this.namename;this.ageage;this.gendergender;}// 3. 方法类型声明参数类型 返回值类型sayHello():string{returnHello, 我是${this.name}${this.age}岁;}// 方法参数类型约束setAge(newAge:number):void{if(newAge0newAge150){this.agenewAge;}}}// 实例化类参数类型必须匹配构造函数constpersonnewPerson(张三,25,男);console.log(person.sayHello());// Hello, 我是 张三25 岁person.setAge(26);// 合法// person.gender 女; // 报错只读属性不能修改// person.setAge(200); // 逻辑上不合法无编译报错需自己写判断1.2 访问修饰符控制属性/方法的访问权限TS 提供 3 种访问修饰符用于控制类的属性和方法在「类内部、子类、外部」的访问权限修饰符访问范围类内部/子类/外部说明public全范围可访问默认类内部、子类、外部都能访问private仅类内部可访问子类和外部都不能访问protected类内部 子类可访问外部不能访问子类可以继承访问classParent{publicpublicProp:stringpublic;// 公开属性privateprivateProp:stringprivate;// 私有属性protectedprotectedProp:stringprotected;// 受保护属性publicpublicMethod(){// 类内部可访问所有属性console.log(this.publicProp,this.privateProp,this.protectedProp);}privateprivateMethod(){console.log(私有方法);}}// 外部访问 Parent 实例constparentnewParent();parent.publicProp;// 合法公开属性parent.publicMethod();// 合法公开方法// parent.privateProp; // 报错私有属性外部不能访问// parent.privateMethod(); // 报错私有方法外部不能访问// 子类继承 ParentclassChildextendsParent{childMethod(){// 子类可访问 public 和 protected 属性不能访问 private 属性console.log(this.publicProp);// 合法console.log(this.protectedProp);// 合法// console.log(this.privateProp); // 报错私有属性子类不能访问this.publicMethod();// 合法// this.privateMethod(); // 报错私有方法子类不能访问}}constchildnewChild();child.publicProp;// 合法// child.protectedProp; // 报错受保护属性外部不能访问child.childMethod();// 合法1.3 抽象类abstract不能实例化只能继承抽象类是「类的模板」用abstract关键字声明不能直接实例化只能被子类继承用于约束子类必须实现特定的方法类似接口但可包含具体实现// 抽象类不能实例化abstractclassAnimal{name:string;constructor(name:string){this.namename;}// 普通方法有具体实现子类可继承eat():void{console.log(${this.name}在吃东西);}// 抽象方法无具体实现用 abstract 声明子类必须实现abstractmakeSound():void;}// 子类继承抽象类必须实现抽象方法 makeSoundclassDogextendsAnimal{// 实现抽象方法方法名、参数、返回值必须与抽象方法一致makeSound():void{console.log(${this.name}汪汪叫);}}classCatextendsAnimal{// 实现抽象方法makeSound():void{console.log(${this.name}喵喵叫);}}// 合法实例化子类constdognewDog(旺财);dog.eat();// 旺财 在吃东西dog.makeSound();// 旺财 汪汪叫constcatnewCat(咪宝);cat.eat();// 咪宝 在吃东西cat.makeSound();// 咪宝 喵喵叫// 报错抽象类不能实例化// const animal new Animal(动物);2. 模块与 TypeScript工程化模块管理TS 支持 ES 模块规范import/export和 CommonJS 规范require/module.exports项目中优先用 ES 模块TS 会自动处理模块类型推导和兼容性。2.1 基础模块导出与导入// src/utils.ts模块文件// 1. 单个导出命名导出exportconstPI:number3.1415;exportfunctionadd(a:number,b:number):number{returnab;}// 2. 多个导出批量命名导出constsubtract(a:number,b:number):numbera-b;constmultiply(a:number,b:number):numbera*b;export{subtract,multiply};// 3. 默认导出一个模块只能有一个默认导出exportdefaultclassCalculator{divide(a:number,b:number):number{if(b0)thrownewError(除数不能为 0);returna/b;}}// src/index.ts导入模块// 1. 导入命名导出必须与导出名称一致可重命名import{PI,add,subtractassub}from./utils;console.log(PI);// 3.1415console.log(add(1,2));// 3console.log(sub(5,3));// 2// 2. 导入默认导出名称可自定义importCalcfrom./utils;constcalcnewCalc();console.log(calc.divide(6,2));// 3// 3. 导入所有导出用 * 接收重命名为 utilsimport*asutilsfrom./utils;console.log(utils.PI);// 3.1415console.log(utils.multiply(2,3));// 62.2 模块类型声明第三方模块无 TS 类型时若第三方模块如某些老的 JS 库没有提供 TS 类型定义文件.d.tsTS 会报错「找不到模块的类型声明」此时需要手动编写「模块类型声明文件」步骤 1新建类型声明文件src/types/index.d.ts// 声明第三方模块 xxx-js-lib 的类型假设模块导出一个函数declaremodulexxx-js-lib{// 声明模块导出的函数类型exportfunctionxxxFn(param:string):void;// 声明模块导出的对象类型exportconstxxxObj:{name:string;version:string;};}步骤 2在tsconfig.json中配置类型声明文件路径{compilerOptions:{typeRoots:[./node_modules/types,./src/types]// 包含自定义类型声明目录}}步骤 3正常导入第三方模块TS 不再报错import{xxxFn,xxxObj}fromxxx-js-lib;xxxFn(test);// 合法TS 识别类型console.log(xxxObj.name);// 合法3. 声明文件.d.ts描述 JS 代码的类型声明文件后缀.d.ts的核心作用是「给 JS 代码提供 TS 类型描述」让 TS 能够识别 JS 代码的类型支持以下场景第三方 JS 库无 TS 类型如老项目、自定义 JS 工具库项目中混合 JS 和 TS给 JS 文件提供类型全局变量/全局函数的类型声明3.1 声明文件基础语法// src/types/global.d.ts全局声明文件// 1. 全局变量声明declareconstVERSION:string;// 全局变量 VERSION类型为 string// 2. 全局函数声明declarefunctionlogMsg(msg:string):void;// 全局函数 logMsg// 3. 全局接口声明可被全局使用interfaceGlobalUser{id:number;name:string;}// 4. 模块声明给 JS 模块提供类型declaremodule./utils.js{exportfunctionformatTime(time:number):string;exportconstnowTime:number;}// src/index.ts使用全局声明console.log(VERSION);// 合法全局变量TS 识别类型logMsg(全局函数调用);// 合法constuser:GlobalUser{id:1,name:张三};// 合法全局接口import{formatTime}from./utils.js;// 合法JS 模块有类型声明formatTime(Date.now());3.2 常用声明文件场景场景 1全局变量声明如 HTML 中引入的全局 JS 变量// 声明 HTML 中通过 script 引入的全局变量 jQuerydeclarevarjQuery:(selector:string)any;// 使用时 TS 不报错jQuery(#app).html(Hello TypeScript);场景 2扩展已有类型如给 String 原型添加方法// 扩展 String 原型添加 reverse 方法declareinterfaceString{reverse():string;}// JS 中实现方法src/utils.jsString.prototype.reversefunction(){returnthis.split().reverse().join();};// TS 中使用无报错识别类型conststrhello;console.log(str.reverse());// olleh4. 高级泛型技巧大型项目实战4.1 泛型工具类型基于泛型的通用类型工具除了 TS 内置的映射类型还有 4 个常用的泛型工具类型用于「类型转换」和「类型提取」覆盖函数返回值、构造函数参数等高频场景工具类型作用基于 T 生成新类型示例ExcludeT, U从 T 中排除「能赋值给 U」的类型Exclude“a”ExtractT, U从 T 中提取「能赋值给 U」的类型Extract“a”ReturnTypeT提取函数 T 的返回值类型ReturnType(a: number)string→ stringConstructorParametersT提取构造函数 T 的参数类型返回元组ConstructorParametersDateConstructor→ [number实战示例// 1. ExcludeT, U排除类型typeAllKeysid|name|age|gender;typeExcludeKeysExcludeAllKeys,age|gender;// 排除 age 和 gender → id | name// 2. ExtractT, U提取类型typeNeedKeysname|address;typeExtractKeysExtractAllKeys,NeedKeys;// 从 AllKeys 提取 NeedKeys 中的类型 → name// 3. ReturnTypeT提取函数返回值类型高频场景// 定义函数functiongetUser():{id:number;name:string}{return{id:1,name:张三};}// 提取返回值类型 → { id: number; name: string }typeUserResReturnTypetypeofgetUser;constuser:UserRes{id:2,name:李四};// 合法// 4. ConstructorParametersT提取构造函数参数类型// Date 构造函数参数类型number | string | Date | nulltypeDateParamsConstructorParametersDateConstructor;constparams1:DateParams[1718000000000];// 合法时间戳constparams2:DateParams[2024-06-10];// 合法字符串日期// 5. 自定义泛型工具类型组合使用// 需求提取对象类型 T 中值为 U 类型的属性名typePickKeysByValueTypeT,U{[KinkeyofT]:T[K]extendsU?K:never;}[keyofT];// 先映射再提取非 never 的属性名typeUser{id:number;name:string;age:number;isActive:boolean};// 提取 User 中值为 number 类型的属性名 → id | agetypeNumKeysPickKeysByValueTypeUser,number;// 提取 User 中值为 boolean 类型的属性名 → isActivetypeBoolKeysPickKeysByValueTypeUser,boolean;4.2 泛型条件类型T extends U ? X : Y动态判断类型泛型条件类型是「基于泛型参数的条件判断动态返回不同类型」语法类似三元运算符核心是「类型层面的条件分支」常用于复杂类型的动态推导// 1. 基础泛型条件类型// 逻辑若 T 是 U 的子类型返回 X 类型否则返回 Y 类型typeConditionalTypeT,U,X,YTextendsU?X:Y;// 示例判断 T 是否为 string 类型是则返回 number否则返回 booleantypeStrToNumTTextendsstring?number:boolean;typeAStrToNumstring;// numberT 是 string返回 XtypeBStrToNumnumber;// booleanT 不是 string返回 YtypeCStrToNumstring|number;// number | boolean联合类型会自动分发分别判断// 2. 泛型条件类型 infer提取类型关键技巧// infer 关键字在条件类型中「提取未知类型」类似变量声明只能在 extends 右侧使用// 需求提取数组的元素类型等价于 TS 内置的 ArrayT[number]typeArrayItemTTextendsArrayinferU?U:T;typeArr1ArrayItemnumber[];// numberT 是数组提取元素类型 UnumbertypeArr2ArrayItemstring[];// stringtypeArr3ArrayItem{id:number};// { id: number }T 不是数组返回自身// 3. 实战场景提取函数的第一个参数类型typeFirstParamTTextends(first:inferU,...rest:any[])?U:never;// 函数(a: number, b: string) voidtypeFn1(a:number,b:string)void;typeParam1FirstParamFn1;// number提取第一个参数类型 Unumber// 函数(name: string) stringtypeFn2(name:string)string;typeParam2FirstParamFn2;// string// 4. 嵌套泛型条件类型复杂逻辑// 需求若 T 是数组返回数组元素的返回值类型若 T 是函数返回函数返回值类型否则返回 TtypeExtractReturnTypeTTextendsArrayinferU?(Uextends(...args:any[])inferR?R:U):Textends(...args:any[])inferR?R:T;// 场景 1T 是函数数组 → 提取函数返回值类型typeFnArr((a:number)string)[];typeRes1ExtractReturnTypeFnArr;// string数组元素是函数返回函数返回值// 场景 2T 是普通函数 → 提取函数返回值类型typeFn(x:string)boolean;typeRes2ExtractReturnTypeFn;// boolean// 场景 3T 是普通数组 → 返回数组元素类型typeNumArrnumber[];typeRes3ExtractReturnTypeNumArr;// number// 场景 4T 是普通对象 → 返回自身typeObj{name:string};typeRes4ExtractReturnTypeObj;// { name: string }5. 枚举Enumenum关键字定义命名常量集合枚举是 TS 新增的「命名常量集合」用于定义一组固定的、有语义的常量如状态码、性别、角色等核心价值是「代码可读性提升」和「避免魔法值」支持数字枚举和字符串枚举。5.1 数字枚举默认值为数字支持自增// 1. 基础数字枚举未指定值时从 0 开始自增enumStatusCode{Success,// 0默认值Error,// 1自增 1Loading// 2自增 1}// 使用枚举通过「枚举名.常量名」访问值为数字console.log(StatusCode.Success);// 0console.log(StatusCode.Error);// 1// 反向映射通过值获取枚举名数字枚举独有console.log(StatusCode[0]);// Success// 2. 指定初始值的数字枚举从指定值开始自增enumRole{Admin100,// 初始值 100User200,// 200手动指定不影响后续自增Guest// 201自增 1}console.log(Role.Admin);// 100console.log(Role.Guest);// 201// 3. 实战场景接口请求状态码enumHttpCode{OK200,BadRequest400,Unauthorized401,Forbidden403,NotFound404,ServerError500}functionhandleResponse(code:HttpCode){switch(code){caseHttpCode.OK:console.log(请求成功);break;caseHttpCode.NotFound:console.log(资源不存在);break;caseHttpCode.ServerError:console.log(服务器错误);break;}}handleResponse(HttpCode.OK);// 请求成功5.2 字符串枚举值为字符串无自增需手动指定字符串枚举的每个常量必须手动指定字符串值不支持反向映射可读性更强常用于描述性的常量// 1. 基础字符串枚举enumGender{MaleMALE,FemaleFEMALE,OtherOTHER}// 使用枚举console.log(Gender.Male);// MALE// 字符串枚举无反向映射以下代码报错// console.log(Gender[MALE]);// 2. 实战场景用户状态描述enumUserStatus{Active已激活,Inactive未激活,Frozen已冻结,Deleted已删除}constuser{id:1,name:张三,status:UserStatus.Active// 语义清晰避免直接写字符串 已激活};if(user.statusUserStatus.Frozen){console.log(用户账号已冻结);}5.3 枚举注意事项枚举会被编译为 JS 代码不是纯类型会增加代码体积编译后是对象数字枚举支持反向映射字符串枚举不支持枚举常量值一旦定义不能修改本质是常量若只需「类型约束」无需运行时常量可改用「字面量联合类型」更轻量// 字面量联合类型替代字符串枚举纯类型无 JS 代码typeGenderMALE|FEMALE|OTHER;constgender:GenderMALE;// 效果与字符串枚举一致更轻量6. 高级类型收窄精准缩小类型范围除了基础类型守卫TS 还支持多种高级类型收窄方式进一步提升类型判断的精准度避免冗余代码6.1 真值收窄if (val)排除 falsy 值通过「真值判断」自动排除null、undefined、0、、false等 falsy 类型functionprintMsg(msg:string|null|undefined){// 真值判断排除 null 和 undefinedTS 自动收窄类型为 stringif(msg){console.log(msg.length);// 合法msg 是 string 类型}else{console.log(msg 为空);// msg 是 null 或 undefined}}printMsg(hello);// 打印 5printMsg(null);// 打印 msg 为空6.2 相等收窄/!判断类型通过「严格相等判断」精准收窄联合类型中的某个类型typeDirectionup|down|left|right;typePosition{x:number;y:number};functionmove(dir:Direction,pos:Position):Position{if(dirup){// dir 收窄为 up 类型return{...pos,y:pos.y-1};}elseif(dirdown){// dir 收窄为 down 类型return{...pos,y:pos.y1};}elseif(dirleft){return{...pos,x:pos.x-1};}else{// dir 收窄为 right 类型TS 自动推导剩余类型return{...pos,x:pos.x1};}}6.3 类型谓词进阶复杂类型收窄结合「泛型 类型谓词」实现通用的复杂类型收窄// 通用类型守卫判断 val 是否为数组且数组元素是 T 类型functionisArrayOfT(val:any,predicate:(item:any)itemisT):valisT[]{returnArray.isArray(val)val.every(predicate);}// 判断是否为 number 类型functionisNumber(val:any):valisnumber{returntypeofvalnumber;}// 判断是否为 string 类型functionisString(val:any):valisstring{returntypeofvalstring;}// 使用通用类型守卫constarr1[1,2,3];if(isArrayOf(arr1,isNumber)){console.log(arr1.reduce((a,b)ab));// 合法arr1 是 number[]}constarr2[a,b,3];if(isArrayOf(arr2,isString)){console.log(arr2.join(,));}else{console.log(数组包含非字符串元素);// 执行此处arr2 有 number 元素}四、TypeScript 配置文件详解tsconfig.jsontsconfig.json是 TS 项目的核心配置文件控制 TS 的编译规则、类型校验严格度、输出目录等强烈推荐开启严格模式strict: true避免类型逃逸以下是关键配置项详解1. 核心编译选项compilerOptions{compilerOptions:{// 1. 基础配置target:ES2020,// 编译后 JS 版本ES3/ES5/ES6/ES2020推荐 ES2020module:ESNext,// 模块规范CommonJS/ESNext/AMD前端推荐 ESNextoutDir:./dist,// 编译后 JS 文件输出目录避免源码和编译文件混合rootDir:./src,// TS 源码目录指定编译范围的根目录lib:[ES2020,DOM],// 编译时依赖的库前端需加 DOMNode.js 不加// 2. 严格模式核心必须开启strict:true,// 开启所有严格类型校验等价于下面 7 个严格选项全为 truenoImplicitAny:true,// 禁止隐式 any 类型变量未指定类型且无法推导时报错strictNullChecks:true,// 严格 null 检查null/undefined 不能赋值给其他类型strictFunctionTypes:true,// 严格函数类型检查避免函数参数类型兼容问题strictPropertyInitialization:true,// 严格属性初始化类属性必须初始化或在构造函数赋值// 3. 模块与路径配置moduleResolution:Bundler,// 模块解析策略Bundler 适配 Vite/RollupNode 适配 Node.jsbaseUrl:./,// 基础路径用于路径别名解析paths:{// 路径别名简化导入路径如 指向 src/*:[src/*]},esModuleInterop:true,// 兼容 CommonJS 和 ESM 模块避免导入 CommonJS 模块报错allowSyntheticDefaultImports:true,// 允许默认导入无默认导出的模块// 4. 类型检查与报错配置noUnusedParameters:true,// 禁止未使用的函数参数提示冗余参数noUnusedLocals:true,// 禁止未使用的局部变量提示冗余变量noImplicitReturns:true,// 禁止函数隐式返回分支必须有 return 或无返回值skipLibCheck:true,// 跳过第三方库的类型检查提升编译速度避免库类型冲突// 5. 输出与调试配置sourceMap:true,// 生成 SourceMap 文件调试时关联 TS 源码开发环境开启生产可关闭declaration:false,// 是否生成类型声明文件 .d.ts库开发开启项目开发关闭removeComments:true,// 编译时移除注释生产环境开启减少代码体积minify:false// 是否压缩编译后的 JS项目开发关闭生产用打包工具压缩},// 2. 编译范围配置include:[./src/**/*],// 需要编译的文件src 目录下所有文件递归匹配exclude:[node_modules,./src/**/*.test.ts],// 排除的文件node_modules、测试文件files:[./src/index.ts],// 指定编译的单个文件与 include 互斥优先 include// 3. 继承配置复用其他配置文件如 tsconfig.base.jsonextends:./tsconfig.base.json}2. 不同场景配置示例场景 1前端项目Vite Vue3/React TS{compilerOptions:{target:ES2020,module:ESNext,outDir:./dist,rootDir:./src,lib:[ES2020,DOM,DOM.Iterable],strict:true,moduleResolution:Bundler,baseUrl:./,paths:{/*:[src/*]},esModuleInterop:true,allowSyntheticDefaultImports:true,sourceMap:true,skipLibCheck:true,noUnusedParameters:true,noUnusedLocals:true},include:[src/**/*],exclude:[node_modules,src/**/*.test.ts]}场景 2Node.js 项目Express TS{compilerOptions:{target:ES2020,module:CommonJS,// Node.js 用 CommonJS 模块outDir:./dist,rootDir:./src,lib:[ES2020],// Node.js 无需 DOM 库strict:true,moduleResolution:Node,// 用 Node 模块解析策略baseUrl:./,paths:{/*:[src/*]},esModuleInterop:true,sourceMap:true,skipLibCheck:true},include:[src/**/*],exclude:[node_modules]}五、TypeScript 实战场景框架集成 项目技巧1. Vue3 TypeScript 集成最常用前端场景Vue3 原生支持 TS配合vitejs/plugin-vue插件可快速搭建 TS 项目核心是「组件 props 类型约束」「响应式数据类型」「生命周期方法类型」。1.1 组件 Props 类型约束3 种方式!-- src/components/HelloWorld.vue -- template div{{ msg }} - {{ user.name }}/div /template script setup langts // 方式 1defineProps 接口推荐结构清晰 interface User { id: number; name: string; age?: number; } interface Props { msg: string; // 必选 prop user: User; // 复杂类型 prop count?: number; // 可选 prop } const props definePropsProps(); // 方式 2defineProps 类型别名 // type Props { // msg: string; // user: { id: number; name: string }; // }; // const props definePropsProps(); // 方式 3defineProps 直接声明简单场景 // const props defineProps{ // msg: string; // user: { id: number; name: string }; // }(); // 访问 propsTS 自动识别类型 console.log(props.msg.length); // msg 是 string 类型 console.log(props.user.id); // user 是 User 类型 /script1.2 响应式数据类型ref/reactivescript setup langts import { ref, reactive, Ref } from vue; // 1. ref 类型基础类型TS 自动推导 const count ref(0); // 自动推导为 Refnumber count.value 1; // 正确value 是 number 类型 // count.value 1; // 报错 // 2. ref 显式声明类型复杂场景如联合类型 const status: Refsuccess | error | loading ref(loading); status.value success; // 合法 // 3. reactive 类型对象类型TS 自动推导 const user reactive({ id: 1, name: 张三, age: 25 }); user.age 26; // 合法 // user.gender 男; // 报错user 无 gender 属性 // 4. reactive 显式声明类型接口/类型别名 interface User { id: number; name: string; hobbies?: string[]; } const user2 reactiveUser({ id: 2, name: 李四, hobbies: [打球, 看书] }); /script1.3 事件处理类型template button clickhandleClick点击/button input inputhandleInput / /template script setup langts // 1. 点击事件MouseEvent 类型 const handleClick (e: MouseEvent) { console.log(e.target); // 正确e 是 MouseEvent 类型 }; // 2. 输入事件InputEvent 类型 const handleInput (e: InputEvent) { // 类型守卫判断 target 是 HTMLInputElement if (e.target instanceof HTMLInputElement) { console.log(e.target.value); // 合法获取输入框值 } }; // 3. 自定义事件defineEmits 声明类型 const emit defineEmits{ (e: change, value: number): void; // 事件名 change参数类型 number (e: update, user: { id: number; name: string }): void; // 事件名 update参数类型 User }(); // 触发自定义事件参数类型必须匹配 emit(change, 100); emit(update, { id: 1, name: 张三 }); /script2. React TypeScript 集成React 与 TS 集成核心是「组件 props 类型」「函数组件类型」「Hooks 类型」配合types/react类型库使用。2.1 函数组件 Props 类型// src/components/Hello.tsx import React from react; // 1. 接口声明 Props 类型推荐 interface HelloProps { name: string; age?: number; // 可选 prop onClick: (msg: string) void; // 函数类型 prop } // 函数组件参数 props 类型为 HelloProps返回值为 React.ReactElement const Hello: React.FCHelloProps (props) { const { name, age 18, onClick } props; return ( div h1Hello {name}, {age} 岁/h1 button onClick{() onClick(Hello ${name})}点击/button /div ); }; export default Hello; // 使用组件参数类型必须匹配 // src/App.tsx import Hello from ./components/Hello; const App () { const handleClick (msg: string) { console.log(msg); }; return ( div Hello name张三 age{25} onClick{handleClick} / /div ); }; export default App;2.2 Hooks 类型约束import React, { useState, useEffect, useRef, useCallback } from react; interface User { id: number; name: string; } const UserComponent () { // 1. useState 类型自动推导或显式声明 const [count, setCount] useState(0); // 自动推导 number 类型 const [user, setUser] useStateUser | null(null); // 显式声明联合类型 // 2. useRef 类型 const inputRef useRefHTMLInputElement(null); // 输入框 DOM 类型 const timerRef useRefNodeJS.Timeout | null(null); // 定时器类型 // 3. useEffect 类型无返回值或返回清理函数 useEffect(() { timerRef.current setInterval(() { setCount(prev prev 1); }, 1000); // 清理函数无返回值类型 return () { if (timerRef.current) clearInterval(timerRef.current); }; }, []); // 4. useCallback 类型指定参数和返回值类型 const handleUpdateUser useCallback((newUser: User) { setUser(newUser); }, []); // 5. 事件处理类型 const handleFocus () { inputRef.current?.focus(); // 可选链操作避免 null 报错 }; return ( div input ref{inputRef} typetext / button onClick{handleFocus}聚焦输入框/button p计数{count}/p button onClick{() handleUpdateUser({ id: 1, name: 张三 })}更新用户/button /div ); }; export default UserComponent;3. Node.js TypeScript 集成Express 示例Node.js 项目用 TS 需配合ts-node直接运行 TS 文件和types/nodeNode.js 类型声明核心是「路由参数类型」「请求响应类型」。3.1 项目初始化与配置安装依赖npminstallexpressnpminstalltypescript ts-node types/node types/express -D生成tsconfig.json{compilerOptions:{target:ES2020,module:CommonJS,outDir:./dist,rootDir:./src,strict:true,moduleResolution:Node,esModuleInterop:true,sourceMap:true},include:[src/**/*],exclude:[node_modules]}package.json 脚本{scripts:{dev:ts-node src/index.ts,// 开发环境运行build:tsc,// 编译 TS 为 JSstart:node dist/index.js// 生产环境运行}}3.2 核心代码示例Express 路由 TS 类型// src/index.tsimportexpress,{Express,Request,Response,NextFunction}fromexpress;constapp:Expressexpress();constport3000;// 中间件解析 JSON 请求体app.use(express.json());// 1. 接口请求/响应类型约束Request/Response 泛型interfaceUser{id:number;name:string;age:number;}// GET 请求获取用户列表Response 泛型指定返回值类型app.get(/api/users,(req:Request,res:ResponseUser[]){constusers:User[][{id:1,name:张三,age:25},{id:2,name:李四,age:30}];res.status(200).json(users);});// 2. 路径参数类型Request 第一个泛型指定 params 类型app.get(/api/users/:id,(req:Request{id:string},res:ResponseUser){constidparseInt(req.params.id);// params.id 是 string 类型需转为 numberconstuser:User{id,name:张三,age:25};res.status(200).json(user);});// 3. 请求体类型Request 第二个泛型指定 body 类型app.post(/api/users,(req:Request{},{},User,res:ResponseUser){constnewUser:User{...req.body};res.status(201).json(newUser);});// 4. 错误处理中间件NextFunction 类型app.use((err:Error,req:Request,res:Response,next:NextFunction){console.error(err.stack);res.status(500).json({message:err.message});});// 启动服务app.listen(port,(){console.log(Server running at http://localhost:${port});});4. TypeScript 项目最佳实践4.1 类型约束原则禁用any类型any会关闭类型校验导致 TS 失去意义可用unknown替代需类型守卫优先类型推导变量声明时直接赋值让 TS 自动推导类型减少冗余代码精准类型定义避免过度使用object、unknown尽量用接口/类型别名定义具体结构开启严格模式strict: true强制严格类型校验提前发现潜在 bug。4.2 性能优化技巧跳过第三方库类型检查skipLibCheck: true避免node_modules中库的类型冲突提升编译速度合理使用exclude排除测试文件、构建产物目录减少编译范围生产环境关闭 SourceMapsourceMap: false减少代码体积使用tsc --incremental增量编译只编译修改的文件提升大型项目编译速度。4.3 代码规范建议类型命名接口/类型别名用 PascalCase大驼峰如User、UserProps泛型参数简单泛型用T、U复杂泛型用语义化名称如User、Props可选属性非必选的属性统一用?标记避免undefined联合类型冗余类型复用重复使用的类型抽离为接口/类型别名避免重复定义注释规范复杂类型添加 JSDoc 注释说明类型含义提升可读性/** * 用户信息类型 * property id - 用户唯一标识 * property name - 用户名必选 * property age - 年龄可选默认 18 */interfaceUser{id:number;name:string;age?:number;}六、TypeScript 常见问题与解决方案1. 类型“null”不能赋值给类型“string”严格 null 检查原因开启strictNullChecks: true后null/undefined不能赋值给其他类型解决方案用联合类型声明或用可选链/非空断言排除 null// 方案 1联合类型声明推荐letmsg:string|nullnull;msghello;// 合法// 方案 2非空断言!确定值不为 null/undefined 时使用constinputdocument.getElementById(input)!;// ! 断言 input 不为 nullinput.valuetest;// 方案 3可选链?.值为 null/undefined 时短路返回 undefinedconstuser:{name?:string}{};console.log(user.name?.length);// 不会报错返回 undefined2. 找不到模块“xxx”的声明文件第三方库无 TS 类型原因第三方 JS 库未提供.d.ts类型声明文件解决方案安装社区类型声明优先npm install types/xxx -D如types/express手动编写类型声明无社区类型时在src/types新建.d.ts文件声明模块临时忽略不推荐// ts-ignore注释跳过该行为的类型检查。3. 函数参数“xxx”没有初始化且没有指定类型原因开启strictPropertyInitialization: true后类属性必须初始化解决方案直接初始化属性在构造函数中赋值用!断言属性会被初始化确定会赋值时classPerson{name:string;// 报错未初始化age:number18;// 方案 1直接初始化gender!:string;// 方案 3! 断言会初始化constructor(name:string){this.namename;// 方案 2构造函数赋值}}4. 类型“string”不能赋值给类型““success” | “error””字面量联合类型原因变量是普通 string 类型无法赋值给固定值的字面量联合类型解决方案用类型断言或类型守卫缩小类型typeStatussuccess|error;// 方案 1类型断言确定值在联合类型中conststatus1:StatussuccessasStatus;// 方案 2类型守卫动态判断值functionisStatus(val:string):valisStatus{return[success,error].includes(val);}conststatusStrsuccess;if(isStatus(statusStr)){conststatus2:StatusstatusStr;// 合法}七、总结TypeScript 作为 JS 的强类型超集核心价值是「提前发现错误、提升开发效率、支撑大型工程」从基础类型到高级泛型从框架集成到项目实战掌握后能显著提升代码质量和开发体验。核心学习路径基础阶段掌握基础类型、数组、元组、函数类型能编写简单 TS 代码进阶阶段吃透联合/交叉类型、接口/类型别名、泛型、类型守卫应对复杂类型场景高级阶段熟练使用映射类型、泛型工具类型、枚举、声明文件适配框架和工程化需求实战阶段结合 Vue3/React/Node.js 项目落地 TS 最佳实践解决实际问题。学习建议边学边练TS 是实践型语言结合小案例练习避免只看理论循序渐进先掌握基础类型和接口再攻克泛型难点逐步深入查阅文档TS 官方文档TypeScript 中文网是最佳学习资料遇到问题优先查文档项目落地在实际项目中使用 TS从简单场景开始逐步覆盖全项目积累实战经验。随着前端工程化的发展TypeScript 已成为大型项目的标配掌握 TS 不仅能提升个人竞争力还能为后续学习框架源码、搭建工程化体系打下坚实基础建议持续深入学习和实践
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站网页价格做网站的技术哪个简单

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 一、unitest基础写法格式1.1引用导入import unittest并且需要新建一个类,继承unittestclass Demo(unittest.TestCase):1.2格式代码示例备注&#xf…

张小明 2025/12/27 16:11:06 网站建设

域名注册查询网站惠州建设厅网站

AWK 数组操作与输出打印全解析 1. AWK 数组基础 AWK 提供一维关联数组,即数组通过字符串值进行索引。可以使用 arr[index] 来引用数组元素,如果该元素不存在,会自动创建。例如: # 示例代码,创建并引用数组元素 awk BEGIN {arr["key1"] = "value1&quo…

张小明 2025/12/28 4:19:35 网站建设

站酷网页用什么工具建设网站

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 构建一个智能代理故障诊断系统,要求:1. 历史故障模式学习 2. 实时网络环境分析 3. 多维度评分系统 4. 自动化修复流程 5. 知识库集成。前端用Electron打包为…

张小明 2025/12/26 13:05:09 网站建设

做网站时尺寸多大上海重大新闻

业务数据图与数据流图全解析 业务数据图中的关系与基数 在业务数据建模中,关系的表示至关重要。以学生和课程为例,学生可以选择任意数量的课程,而课程也可以有零到无限数量的学生报名,这体现了学生与课程之间的多对多关系,如下所示: graph LRclassDef process fill:#…

张小明 2025/12/26 13:04:35 网站建设

做网站能赚钱wordpress中文设置方法

基于SpringBoot的商场停车场管理系统设计与实现 第一章 系统开发背景与现实意义 商场作为人流车流密集场所,传统停车场管理模式痛点突出:高峰时段车主找位耗时久,易造成入口拥堵;缴费依赖人工窗口或扫码桩,排队等待影响…

张小明 2025/12/26 13:04:02 网站建设

网站开发常用的前端框架wordpress搭建app

DNS服务器配置与DHCP池及故障转移设置 1. DNS服务器配置 1.1 创建区域传输密钥 当我们需要创建用于区域传输的密钥时,可以使用 dnssec-keygen 命令。使用该命令后,会在当前目录生成两个文件: - *.key 文件:包含DNS KEY记录,可使用 include 语句将其包含在区域文…

张小明 2025/12/26 13:03:28 网站建设