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

重新认识Typescript-Vue3源码系列

时间:2023-03-23 10:50:04 科技观察

初会。官方只用了一句话来形容TypeScript是JavaScript的类型化超集,可以编译成纯JavaScript。任何浏览器。任何主机。任何操作系统。开源。大致意思就是,TypeScript是开源的,TypeScript是JavaScript的类型超集,可以编译成纯JavaScript。编译后的JavaScript可以在任何浏览器上运行。TypeScript编译工具可以运行在任何服务器和任何系统上。问题:什么是超集?超集是集合论中的一个术语。说到超集,就不得不说另一个,子集。怎么理解这两个概念?举个例子如果集合A中的所有元素都存在于集合B中,那么我们可以理解集合A是集合B的子集,否则集合B是集合A的超集。现在我们可以理解Typescript包含了所有Javascript的特性,这也意味着我们可以直接将.js后缀命名为.ts文件,运行到TypeScript编译系统。Typescript解决了什么问题?一个事物的诞生必然有其存在的价值。那么Typescript的价值是什么?在回答这个问题之前,我们需要先了解一下Typescript的工作哲学,本质上就是在JavaScript中加入一个静态类型系统(编译时的类型分析),强调静态类型系统是为了运行时的类型检查机制区分的,TypeScript代码最终会被编译成JavaScript让我们回到问题本身,缩小范围。Typescript创造的大部分价值体现在开发时(编译时)而非运行时,例如强大的编辑器智能提示(研发效率、开发体验)增强的代码可读性(团队协作、开发体验)编译时类型检查(稳定business,前端项目中Top10的错误类型和低级类型错误占比70%)Text本文作为Vue3源码系列前导之一,Typescript的科普文章,主要目的是为了让你在面对Vue3源码的时候不那么不知所措。接下来,我将介绍Typescript的一些基本用法。变量声明基本类型letisDone:boolean=falseletnum:number=1letstr:string='vue3js.cn'letarr:number[]=[1,2,3]letarr2:Array=[1,2,3]//通用数组letobj:Object={}letu:undefined=undefined;letn:null=null;类型补充enumerationEnum使用枚举类型给一组值起一个友好的名字enumLogLevel{info='info',warn='warn',error='error',}TupleTuple允许数组每个元素的类型不必相同。例如,你可以定义一对值为字符串和数字的元组。hello'];//ErrorAnyvalueAny表示任意类型,通常用于不确定的内容类型,比如来自用户输入或第三方代码库letnotSure:any=4;notSure="maybeastringinstead";notSure=false;//okay,definitelyabooleanvoid和any相反,一般用在函数中,表示没有返回值服务器接口,首先要定义一个字段的推理如下。比如point和Point必须是同一个类型,不能多一个或者少一个。interfacePoint{x:numbery:numberz?:numberreadonlyl:number}constpoint:Point={x:10,y:20,z:30,l:40}constpoint2:Point={x:'10',y:20,z:30,l:40}//Errorconstpoint3:Point={x:10,y:20,z:30}//Errorconstpoint4:Point={x:10,y:20,z:30,l:40,m:50}//错误可选还是只读?表示可选参数,readonly表示只读constpoint5:Point={x:10,y:20,l:40}//正常point5.l=50//错误函数参数类型和返回值类型functionsum(a:number,b:number):number{returna+b}配合interface使用interfacePoint{x:numbery:number}functionsum({x,y}:Point):number{returnx+y}sum({x:1,y:2})//3泛型泛型的意义在于函数的复用性。设计原则希望组件不仅可以支持当前的数据类型,还可以支持未来的数据类型。比如根据原来业务设计函数identity入参为Stringfunctionidentity(arg:String){returnarg}console.log(identity('100'))业务迭代过程参数需要支持Numberfunctionidentity(arg:String){returnarg}console.log(identity(100))//Argumentoftype'100'isnotassignabletoparameteroftype'String'.为什么不使用任何?使用any会丢失一些信息,我们无法确定返回值是什么类型。泛型可以保证输入参数和返回值的类型相同。它是一个特殊的变量,只用于表示类型而不是值语法(arg:T):T其中T是自定义变量consthello:string="Helovue!"functionsay(arg:T):T{returnarg;}console.log(say(hello))//你好!泛型约束我们使用同样的例子,添加一个控制台,但是不幸的是,报错了,因为泛型不能保证每个类型都有.length属性consthello:string="Helovue!"functionsay(arg:T):T{console.log(arg.length)//属性'length'doesnotexistontype'T'.returnarg;}console.log(say(hello))//你好!从这里我们也和any还有一个不同的是,如果我们想在约束层结束战斗,我们需要定义一个接口来描述约束interfaceLengthwise{length:number;}functionsay(arg:T):T{console.log(arg.length)返回参数;}console.log(say(1))//参数entoftype'1'isnotassignabletoparameteroftype'Lengthwise'.console.log(say({value:'hellovue!',length:10}))//{value:'hellovue!',length:10}intersectiontypeintersectiontype(IntersectionTypes),将多种类型合并为一种类型interfacefoo{x:number}interfacebar{b:number}typeintersection=foo&barconstresult:intersection={x:10,b:20}constresult1:intersection={x:10}//错误联合类型交集类型(UnionTypes),表示一个值可以是几种类型中的一种我们用竖线|分隔每种类型,所以数|字符串|boolean表示值可以是数字、字符串或布尔值typearg=string|number|booleanconstfoo=(arg:arg):any=>{console.log(arg)}foo(1)foo('2')foo(true)函数重载函数重载(FunctionOverloading),允许创建多个同名但输入输出类型或数量不同的子程序,可以简单理解为一个函数执行多个任务的能力比如我们有一个addfunction,可以接收字符串型参数进行拼接,也可以接收数字型参数进行加法functionadd(arg1:string,arg2:string):stringfunctionadd(arg1:number,arg2:number):number//实现functionadd(arg1:T,arg2:U){//在实现上要注意严格判断两个参数的类型是否相等,而不是简单写一个arg1+arg2if(typeofarg1==='string'&&typeofarg2==='string'){returnarg1+arg2}elseif(typeofarg1==='number'&&typeofarg2==='number'){returnarg1+arg2}}add(1,2)//3add('1','2')//'12'Summary通过这篇文章,相信你对Typescript不会再陌生了。下面我们来看看Vue源码中Typescript是怎么写的。这里我们以defineComponent函数为例。大家可以通过这个例子,结合文章的内容来理解和加深对Typescript的理解|渲染函数tion):{new():ComponentPublicInstance}&FunctionalComponent//defineComponent有四个重载,这里省略三个//实现,cloestono-opexportfunctiondefineComponent(选项:未知){returnisFunction(选项)?{设置:选项}:选项}