当前位置: 首页 > 科技观察

学TSinfer,写泛型真香!

时间:2023-03-17 12:21:53 科技观察

你知道如何获取T0数组类型中元素的类型和T1函数类型中的返回值类型吗?给你3秒钟的时间考虑一下。输入T0=字符串[];输入T1=()=>字符串;要实现以上功能,我们可以使用TypeScript提供的类型模式匹配技术——条件类型+推断。条件类型允许我们检测两种类型之间的关系,通过这种关系我们可以确定两种类型是否兼容。而infer用于声明类型变量,用来存储模式匹配时捕获到的类型。我们来看看如何捕获T0数组类型中元素的类型:typeUnpackedArray=Textends(inferU)[]?U:TtypeU0=UnpackedArray//string在上面的代码中,Textends(inferU)[]?U:T是条件类型的语法,extends子句中的inferU引入了一个新的类型变量U来存储推断的类型。为了方便大家理解,我们来演示一下UnpackedArray工具类型的执行流程。typeU0=UnpackedArray//T=>T0:string[]typeUnpackedArray=string[]extends(inferU)[]?U:string[]//string[]extends(inferU)[]模式匹配成功//U=>string需要注意的是,infer只能用在条件类型的extends子句中,声明的类型变量byinfer只能用在条件类型的真分支中。typeWrong1=T[0]//ErrortypeWrong2=(inferU)[]extendsT?U:T//错误类型Wrong3=Textends(inferU)[]?T:U//Error了解了这些知识后,我们来看看如何获??取T1函数的返回值类型你?U:T;类型U1=UnpackedFn;//string看了UnpackedFn工具类的实现,是不是觉得挺简单的。当遇到函数重载场景时,TypeScript会使用最后的调用签名进行类型推断:declarefunctionfoo(x:string):number;declarefunctionfoo(x:number):string;declarefunctionfoo(x:string|number):串|数字;类型UnpackedFn=Textends(...args:any[])=>inferU?U:T;typeU2=UnpackedFn;//字符串|如果你还不知道TypeScript的条件类型,建议阅读《使用TS条件类型,同事直接调用YYDS》一文。在本文中,我们介绍了条件链,我们可以使用它来实现更强大的Unpacked工具类型。输入Unpacked=Textends(inferU)[]?U:Textends(...args:any[])=>inferU?U:TextendsPromise?U:T;typeT0=Unpacked;//字符串类型T1=Unpacked;//stringtypeT2=Unpacked<()=>string>;//字符串类型T3=Unpacked>;//字符串类型T4=Unpacked[]>;//PromisetypeT5=Unpacked[]>>;//string上面代码中,Unpacked工具类型利用条件类型和条件链,轻松实现推断数组类型中元素类型、函数返回值类型、类型的功能Promise类型中的返回值。事实上,使用条件类型和推断,我们也可以推断出对象类型中键的类型。接下来,我们举一个具体的例子:typeUser={id:number;name:string;}typePropertyType=Textends{id:inferU,name:inferR}?[U,R]:TtypeU3=PropertyType//[number,string]在PropertyType工具类型中,我们通过infer声明了两个类型变量U和R,分别代表了id和name属性中的类型对象类型。如果类型匹配,我们将id和name属性的类型作为元组返回。那么现在的问题是,在PropertyType工具类型中,如果只声明一个类型变量U,结果会是什么?让我们验证一下:typePropertyType=Textends{id:inferU,name:inferU}?U:TtypeU4=PropertyType//字符串|number从上面的代码可以看出,U4类型返回的是一个由string和number类型组成的联合类型。为什么会返回这样的结果?这是因为在协变的位置上,如果同一类型变量有多个候选,最终的类型会被推断为联合类型。但是,在逆变位置,如果同一类型变量有多个候选,则最终类型将被推断为交集类型。同样,让我们??实际验证:typeBar=Textends{a:(x:inferU)=>void,b:(x:inferU)=>void}?U:never;typeU5=Bar<{a:(x:string)=>void,b:(x:number)=>void}>;//string&number上面代码中,U5类型返回了一个string和number类型组成的交集类型,即最终的类型是nevertype。看完这篇文章,相信你已经明白了条件类型和推断的作用。那么你能看懂UnionToIntersection工具类型的具体实现吗?类型UnionToIntersection=(Uextendsany?(arg:U)=>void:never)extends(arg:inferR)=>void?R:从不