TypeScript类型体操高级类型编程全攻略

TypeScript类型体操高级类型编程全攻略 TypeScript类型体操:高级类型编程全攻略从基础泛型到复杂类型推导,掌握TypeScript类型系统的精髓前言TypeScript的类型系统是图灵完备的——这意味着你可以在类型层面进行任意复杂的计算。很多开发者对TypeScript的理解停留在interface和type的基础用法,遇到复杂的类型场景就束手无策。本文将从基础到进阶,系统讲解TypeScript的高级类型编程技巧,包括条件类型、映射类型、模板字面量类型、递归类型等,配合大量实战案例,帮你从"会写类型"进阶到"玩转类型"。一、类型系统基础回顾1.1 基础类型// 原始类型letstr:string="hello";letnum:number=42;letbool:boolean=true;letnul:null=null;letundef:undefined=undefined;letsym:symbol=Symbol("key");letbig:bigint=100n;// 特殊类型letany:any="anything";// 任意类型,关闭类型检查letunknown:unknown="unknown";// 安全的any,使用前必须类型检查letnever:never;// 永远不会有值的类型letvoid_:void;// 函数无返回值// 数组letarr:number[]=[1,2,3];letarr2:Arraynumber=[1,2,3];// 元组lettuple:[string,number]=["hello",42];1.2 联合类型与交叉类型// 联合类型:A | B(取并集,可以是A或B)typeStringOrNumber=string|number;letval:StringOrNumber="hello";// OKval=42;// OK// val = true; // Error// 交叉类型:A B(取交集,同时是A和B)typeNamed={name:string};typeAged={age:number};typePerson=NamedAged;letperson:Person={name:"Alice",age:30};// OK// let person2: Person = { name: "Bob" }; // Error: 缺少age属性// 联合类型的类型收窄functionprocess(value:string|number){if(typeofvalue==="string"){// 这里value被收窄为string类型console.log(value.toUpperCase());}else{// 这里value被收窄为number类型console.log(value.toFixed(2));}}1.3 泛型基础// 泛型函数functionidentityT(arg:T):T{returnarg;}// 泛型约束functiongetPropertyT,KextendskeyofT(obj:T,key:K):T[K]{returnobj[key];}// 泛型接口interfaceRepositoryT{findById(id:string):PromiseT|null;findAll():PromiseT[];save(entity:T):PromiseT;delete(id:string):Promisevoid;}// 泛型类classStackT{privateitems:T[]=[];push(item:T):void{this.items.push(item);}pop():T|undefined{returnthis.items.pop();}}二、条件类型(Conditional Types)2.1 基本语法// 语法:T extends U ? X : Y// 如果T是U的子类型,则为X,否则为YtypeIsStringT=Textendsstring?true:false;typeA=IsStringstring;// truetypeB=IsStringnumber;// falsetypeC=IsString"hello";// true(字面量类型是string的子类型)2.2 infer关键字infer用于在条件类型中推断(提取)类型:// 提取函数返回类型typeReturnTypeT=Textends(...args:any[])=inferR?R:never;typeR1=ReturnType()=string;// stringtypeR2=ReturnType(x:number)=boolean;// boolean// 提取函数参数类型typeParametersT=Textends(...args:inferP)=any?P:never;typeP1=Parameters(a:string,b:number)=void;// [a: string, b: number]// 提取Promise的值类型typeAwaitedT=TextendsPromiseinferU?AwaitedU:T;typeA1=AwaitedPromisestring;// stringtypeA2=AwaitedPromisePromisenumber;// number(递归提取)// 提取数组元素类型typeElementTypeT=Textends(inferE)[]?E:never;typeE1=ElementTypestring[];// stringtypeE2=ElementTypenumber[];// number2.3 分布式条件类型当条件类型作用于联合类型时,会自动分布(distribute)到每个成员:// 分布式条件类型typeToArrayT=Textendsany?T[]:never;typeR=ToArraystring|number;// 等价于:// ToArraystring | ToArraynumber// = string[] | number[]// 不是 (string | number)[]// 阻止分布式行为typeToArrayNonDistT=[T]extends[any]?T[]:never;typeR2=ToArrayNonDiststring|number;// = (string | number)[]2.4 实战:Extract与Exclude// Extract:从联合类型中提取满足条件的类型typeExtractT,U=TextendsU?T:never;typeE=Extractstring|number|boolean,string|boolean;// = string | boolean// Exclude:从联合类型中排除满足条件的类型typeExcludeT,U=TextendsU?never:T;typeE2=Excludestring|number|boolean,string|boolean;// = number// 实际应用:过滤函数类型typeNonFunctionT=TextendsFunction?never:T;typeObj={name:string;age:number;greet:()=void;calculate:(x:number)=number;};typeDataOnly={[KinkeyofObjasObj[K]extendsFunction?never:K]:Obj[K];};// = { name: string; age: number }三、映射类型(Mapped Types)