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

说说Typescript的进阶技巧

时间:2023-03-19 13:59:00 科技观察

在使用了一段时间的typescript之后,深感中大型项目中typescript的必要性。可以提前避免很多编译时的bug,比如恶心的拼写问题。而且越来越多的包开始使用ts,学习ts势在必行。下面是我在工作中总结的比较实用的typescript技巧。01keyofkeyof和Object.keys有点类似,只是keyof取的是界面的key。interfacePoint{x:number;y:number;}//typekeys="x"|"y"typekeys=keyofPoint;假设有一个如下图所示的对象,我们需要使用typescript实现一个get函数来获取它的属性值constdata={a:3,hello:'world'}functionget(o:object,name:string){returno[name]}一开始我们可能会这样写,但是它有很多缺点,不能确认返回类型:这样会失去tsmax_.get的类型验证功能不能约束key:你可能会拼写错误。这时候可以使用keyof来加强get函数的类型功能。有兴趣的同学可以看看_.get的type标签和函数get(o:T,name:K):T[K]{returno[name]}02Required&Partial&PickNow的实现如果你了解keyof,你可以用它来对属性做一些扩展,比如实现Partial和Pick,Pick一般用在_.picktypePartial={[PinkeyofT]?:T[P];};typeRequired={[PinkeyofT]-?:T[P];};typePick={[PinK]:T[P];};interfaceUser{id:number;age:number;name:string;};//等同于:typePartialUser={id?:number;age?:number;name?:string;}typePartialUser=Partial//等同于:typePickUser={id:number;age:number;}typePickUser=Pick这些类型已经内置到Typescript03ConditionType类中类似于js中的?:运算符,可以用它来扩展一些基本类型TextendsU?X:YtypeisTrue=Textendstrue?true:false//等同于typet=falsetypet=isTrue//等同于typet=falsetypet1=isTrue04never&Exclude&Omit官方文档对never的描述是这样的:never类型代表的是永远不会出现的值的类型。结合never和条件类型可以引入很多有趣实用的类型,比如OmittypeExclude=TextendsU?never:T;//等价于:typeA='a'typeA=Exclude<'x'|'a','x'|'y'|'z'>结合Exclude可以引入Omit的写法typeOmit=Pick>;interfaceUser{id:number;age:number;name:string;};//相当于:typePickUser={age:number;name:string;}typeOmitUser=Omit05typeof顾名思义,typeof表示取某个值的类型,它们的用法可以从下面的例子中看出consta:number=3//等价于:constb:number=4constb:typeofa=4在一个典型的服务端项目中,我们往往需要在上下文中插入一些工具,比如config、logger、dbmodels、utils等,这时候就用到了typeofimportloggerfrom'./logger'importutilsfrom'./utils'interfaceContexttextendsKoaContect{logger:typeoflogger,utils:typeofutils}app.use((ctx:Context)=>{ctx.logger.info('hello,world')//会报告一个error,因为logger.ts中没有暴露这个方法,所以可以最大程度的避免拼写错误。ctx.loger.info('hello,world')})06是Error集中处理,识别的过程代码app.use(async(ctx,next)=>{try{awaitnext();}catch(err){letcode='BAD_REQUEST'if(err.isAxiosError){code=`Axios-${err.code}`}elseif(errinstanceofSequelize.BaseError){}ctx.body={code}}})在err.code处会出现编译错误,提示Property'code'doesnotexistontype'Error'.ts(2339)。这时候可以使用asAxiosError或者asany来避免报错,但是强制类型转换不够友好if((errasAxiosError).isAxiosError){code=`Axios-${(errasAxiosError).code}`}这个时候,可以使用是判断值类型的函数isAxiosError(error:any):errorisAxiosError{returnerror.isAxiosError}if(isAxiosError(err)){code=`Axios-${err.code}`}源码中GraphQL的代码,有很多这样的用法,识别类型;07interface&type接口和类型有什么区别?可以参考下面的stackoverflow问题https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types一般来说,接口和类型的区别是很小。比如下面两种写法类似interfaceA{a:number;b:number;};typeB={a:number;b:number;}其中interface可以这样组合,type只能是通过&类连接。interfaceA{a:number;}interfaceA{b:number;}consta:A={a:3,b:4}08Record&Dictionary&Many这些语法糖是从lodash的types源码中学来的,平时工作中的使用频率相当高。typeRecord={[PinK]:T;};interfaceDictionary{[index:string]:T;};interfaceNumericDictionary{[index:number]:T;};constdata:Dictionary={a:3,b:4}09使用constenum维护常量表与使用文字对象维护常量相比,constenum可以提供更安全的类型检查//使用对象维护常量constTODO_STATUS{TODO:'TODO',DONE:'DONE',DOING:'DOING'}//使用constenum保持常数constenumTODO_STATUS{TODO='TODO',DONE='DONE',DOING='DOING'}functiontodos(status:TODO_STATUS):Todo[];todos(TODO_STATUS.TODO)10VSCodeTips&Typescript命令在使用VSCode的时候,有时用tsc编译产生的问题和vscode提示的问题不一致。在项目右下角找到Typescript字样,右边显示的是它的版本号。可以点击选择UseWorkspaceVersion,即与项目所依赖的typescript版本一致。或者编辑.vs-code/settings.json{"typescript.tsdk":"node_modules/typescript/lib"}11TypescriptRoadmap最后也是最重要的一项,阅读Roadmap了解一些新特性和bug修复TS。参考https://www.typescriptlang.org/docs/handbook/advanced-types.htmlhttps://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.htmlhttps:///moin.world/2017/06/18/10-typescript-features-you-might-not-know/本文转载自微信公众号“全栈成长之路”,可通过以下二维码关注代码。转载本文请联系全栈成长之路公众号。