当前位置:首页 > 通信资讯 > 正文

typescript 入门(一站掌握TypeScript 基础入门+语法进阶+高级语法)

用了一段时间的 typescript 之后,深感中大型项目中 typescript 的必要性,它能够提前在编译期避免许多 bug,如很恶心的拼写问题。而越来越多的 package 也开始使用 ts,学习 ts 已是势在必行。

以下是我在工作中总结到的比较实用的 typescript 技巧。

01 keyof

keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键。

  1. interfacePoint{
  2. x:number;
  3. y:number;
  4. }
  5. //typekeys="x"|"y"
  6. typekeys=keyofPoint;

假设有一个 object 如下所示,我们需要使用 typescript 实现一个 get 函数来获取它的属性值

  1. constdata={
  2. a:3,
  3. hello:'world'
  4. }
  5. functionget(o:object,name:string){
  6. returno[name]
  7. }

我们刚开始可能会这么写,不过它有很多缺点

  • 无法确认返回类型:这将损失 ts 最大的类型校验功能
  • 无法对 key 做约束:可能会犯拼写错误的问题

这时可以使用 keyof 来加强 get 函数的类型功能,有兴趣的同学可以看看 _.get 的 type 标记以及实现

  1. functionget<Textendsobject,KextendskeyofT>(o:T,name:K):T[K]{
  2. returno[name]
  3. }

02 Required & Partial & Pick

既然了解了 keyof,可以使用它对属性做一些扩展, 如实现 Partial 和 Pick,Pick 一般用在 _.pick 中

  1. typePartial<T>={
  2. [PinkeyofT]?:T[P];
  3. };
  4. typeRequired<T>={
  5. [PinkeyofT]-?:T[P];
  6. };
  7. typePick<T,KextendskeyofT>={
  8. [PinK]:T[P];
  9. };
  10. interfaceUser{
  11. id:number;
  12. age:number;
  13. name:string;
  14. };
  15. //相当于:typePartialUser={id?:number;age?:number;name?:string;}
  16. typePartialUser=Partial<User>
  17. //相当于:typePickUser={id:number;age:number;}
  18. typePickUser=Pick<User,"id"|"age">

这几个类型已内置在 Typescript 中

03 Condition Type

类似于 js 中的 ?: 运算符,可以使用它扩展一些基本类型

  1. TextendsU?X:Y
  2. typeisTrue<T>=Textendstrue?true:false
  3. //相当于typet=false
  4. typet=isTrue<number>
  5. //相当于typet=false
  6. typet1=isTrue<false>

04 never & Exclude & Omit

官方文档对 never 的描述如下

the never type represents the type of values that never occur.

结合 never 与 conditional type 可以推出很多有意思而且实用的类型,比如 Omit

  1. typeExclude<T,U>=TextendsU?never:T;
  2. //相当于:typeA='a'
  3. typeA=Exclude<'x'|'a','x'|'y'|'z'>

结合 Exclude 可以推出 Omit 的写法

  1. typeOmit<T,Kextendskeyofany>=Pick<T,Exclude<keyofT,K>>;
  2. interfaceUser{
  3. id:number;
  4. age:number;
  5. name:string;
  6. };
  7. //相当于:typePickUser={age:number;name:string;}
  8. typeOmitUser=Omit<User,"id">

05 typeof

顾名思义,typeof 代表取某个值的 type,可以从以下示例来展示他们的用法

  1. consta:number=3
  2. //相当于:constb:number=4
  3. constb:typeofa=4

在一个典型的服务端项目中,我们经常需要把一些工具塞到 context 中,如config,logger,db models, utils 等,此时就使用到 typeof。

  1. importloggerfrom'./logger'
  2. importutilsfrom'./utils'
  3. interfaceContextextendsKoaContect{
  4. logger:typeoflogger,
  5. utils:typeofutils
  6. }
  7. app.use((ctx:Context)=>{
  8. ctx.logger.info('hello,world')
  9. //会报错,因为logger.ts中没有暴露此方法,可以最大限度的避免拼写错误
  10. ctx.loger.info('hello,world')
  11. })

06 is

在此之前,先看一个 koa 的错误处理流程,以下是对 error 进行集中处理,并且标识 code 的过程

  1. app.use(async(ctx,next)=>{
  2. try{
  3. awaitnext();
  4. }catch(err){
  5. letcode='BAD_REQUEST'
  6. if(err.isAxiosError){
  7. code=`Axios-${err.code}`
  8. }elseif(errinstanceofSequelize.BaseError){
  9. }
  10. ctx.body={
  11. code
  12. }
  13. }
  14. })

在 err.code 处,会编译出错,提示 Property 'code' does not exist on type 'Error'.ts(2339)。

此时可以使用 as AxiosError 或者 as any 来避免报错,不过强制类型转换也不够友好

  1. if((errasAxiosError).isAxiosError){
  2. code=`Axios-${(errasAxiosError).code}`
  3. }

此时可以使用 is 来判定值的类型

  1. functionisAxiosError(error:any):errorisAxiosError{
  2. returnerror.isAxiosError
  3. }
  4. if(isAxiosError(err)){
  5. code=`Axios-${err.code}`
  6. }

在 GraphQL 的源码中,有很多诸如此类的用法,用以标识类型

  1. exportfunctionisType(type:any):typeisGraphQLType;
  2. exportfunctionisScalarType(type:any):typeisGraphQLScalarType;
  3. exportfunctionisObjectType(type:any):typeisGraphQLObjectType;
  4. exportfunctionisInterfaceType(type:any):typeisGraphQLInterfaceType;

07 interface & type

interface 与 type 的区别是什么?可以参考以下 stackoverflow 的问题

https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types

一般来说,interface 与 type 区别很小,比如以下两种写法差不多

  1. interfaceA{
  2. a:number;
  3. b:number;
  4. };
  5. typeB={
  6. a:number;
  7. b:number;
  8. }

其中 interface 可以如下合并多个,而 type 只能使用 & 类进行连接。

  1. interfaceA{
  2. a:number;
  3. }
  4. interfaceA{
  5. b:number;
  6. }
  7. consta:A={
  8. a:3,
  9. b:4
  10. }

08 Record & Dictionary & Many

这几个语法糖是从 lodash 的 types 源码中学到的,平时工作中的使用频率还挺高。

  1. typeRecord<Kextendskeyofany,T>={
  2. [PinK]:T;
  3. };
  4. interfaceDictionary<T>{
  5. [index:string]:T;
  6. };
  7. interfaceNumericDictionary<T>{
  8. [index:number]:T;
  9. };
  10. constdata:Dictionary<number>={
  11. a:3,
  12. b:4
  13. }

09 使用 const enum 维护常量表

相比使用字面量对象维护常量,const enum 可以提供更安全的类型检查

  1. //使用object维护常量
  2. constTODO_STATUS{
  3. TODO:'TODO',
  4. DONE:'DONE',
  5. DOING:'DOING'
  6. }
  1. //使用constenum维护常量
  2. constenumTODO_STATUS{
  3. TODO='TODO',
  4. DONE='DONE',
  5. DOING='DOING'
  6. }
  7. functiontodos(status:TODO_STATUS):Todo[];
  8. todos(TODO_STATUS.TODO)

10 VS Code Tips & Typescript Command

使用 VS Code 有时会出现,使用 tsc 编译时产生的问题与 vs code 提示的问题不一致

找到项目右下角的 Typescript 字样,右侧显示它的版本号,可以点击选择 Use Workspace Version,它表示与项目依赖的 typescript 版本一直。

或者编辑 .vs-code/settings.json

  1. {
  2. "typescript.tsdk":"node_modules/typescript/lib"
  3. }

11 Typescript Roadmap

最后一条也是最重要的一条,翻阅 Roadmap,了解 ts 的一些新的特性与 bug 修复情况。

参考

https://www.typescriptlang.org/docs/handbook/advanced-types.html

https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html

https://moin.world/2017/06/18/10-typescript-features-you-might-not-know/

文章来源:https://mp.weixin.qq.com/s/-6qTDjTgMQTWDlIjvXZ3rQ

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。