服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - 聊一聊Typescript 高级技巧

聊一聊Typescript 高级技巧

2021-08-04 22:52全栈成长之路山月行 编程技术

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

聊一聊Typescript 高级技巧

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

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

01 keyof

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

  1. interface Point { 
  2.     x: number; 
  3.     y: number; 
  4.  
  5. // type keys = "x" | "y" 
  6. type keys = keyof Point; 

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

  1. const data = { 
  2.   a: 3, 
  3.   hello: 'world' 
  4.  
  5. function get(o: object, name: string) { 
  6.   return o[name

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

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

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

  1. function get<T extends object, K extends keyof T>(o: T, name: K): T[K] { 
  2.   return o[name

02 Required & Partial & Pick

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

  1. type Partial<T> = { 
  2.   [P in keyof T]?: T[P]; 
  3. }; 
  4.  
  5. type Required<T> = { 
  6.   [P in keyof T]-?: T[P]; 
  7. }; 
  8.  
  9. type Pick<T, K extends keyof T> = { 
  10.   [P in K]: T[P]; 
  11. }; 
  12.  
  13. interface User { 
  14.   id: number; 
  15.   age: number; 
  16.   name: string; 
  17. }; 
  18.  
  19. // 相当于: type PartialUser = { id?: number; age?: number; name?: string; } 
  20. type PartialUser = Partial<User
  21.  
  22. // 相当于: type PickUser = { id: number; age: number; } 
  23. type PickUser = Pick<User"id" | "age"

这几个类型已内置在 Typescript

03 Condition Type

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

  1. T extends U ? X : Y 
  2.  
  3. type isTrue<T> = T extends true ? true : false 
  4. // 相当于 type t = false 
  5. type t = isTrue<number> 
  6.  
  7. // 相当于 type t = false 
  8. type t1 = isTrue<false

04 never & Exclude & Omit

官方文档对 never 的描述如下

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

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

  1. type Exclude<T, U> = T extends U ? never : T; 
  2.  
  3. // 相当于: type A = 'a' 
  4. type A = Exclude<'x' | 'a''x' | 'y' | 'z'

结合 Exclude 可以推出 Omit 的写法

  1. type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>; 
  2.  
  3. interface User { 
  4.   id: number; 
  5.   age: number; 
  6.   name: string; 
  7. }; 
  8.  
  9. // 相当于: type PickUser = { age: number; name: string; } 
  10. type OmitUser = Omit<User"id"

05 typeof

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

  1. const a: number = 3 
  2.  
  3. // 相当于: const b: number = 4 
  4. const b: typeof a = 4 

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

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

06 is

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

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

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

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

  1. if ((err as AxiosError).isAxiosError) { 
  2.   code = `Axios-${(err as AxiosError).code}` 

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

  1. function isAxiosError (error: any): error is AxiosError { 
  2.   return error.isAxiosError 
  3.  
  4. if (isAxiosError(err)) { 
  5.   code = `Axios-${err.code}` 

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

  1. export function isType(type: any): type is GraphQLType; 
  2.  
  3. export function isScalarType(type: any): type is GraphQLScalarType; 
  4.  
  5. export function isObjectType(type: any): type is GraphQLObjectType; 
  6.  
  7. export function isInterfaceType(type: any): type is GraphQLInterfaceType; 

07 interface & type

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

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

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

  1. interface A { 
  2.   a: number; 
  3.   b: number; 
  4. }; 
  5.  
  6. type B = { 
  7.   a: number; 
  8.   b: number; 

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

  1. interface A { 
  2.     a: number; 
  3.  
  4. interface A { 
  5.     b: number; 
  6.  
  7. const a: A = { 
  8.     a: 3, 
  9.     b: 4 

08 Record & Dictionary & Many

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

  1. type Record<K extends keyof any, T> = { 
  2.     [P in K]: T; 
  3. }; 
  4.  
  5. interface Dictionary<T> { 
  6.   [index: string]: T; 
  7. }; 
  8.  
  9. interface NumericDictionary<T> { 
  10.   [index: number]: T; 
  11. }; 
  12.  
  13. const data:Dictionary<number> = { 
  14.   a: 3, 
  15.   b: 4 

09 使用 const enum 维护常量表

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

  1. // 使用 object 维护常量 
  2. const TODO_STATUS { 
  3.   TODO: 'TODO'
  4.   DONE: 'DONE'
  5.   DOING: 'DOING' 
  1. // 使用 const enum 维护常量 
  2. const enum TODO_STATUS { 
  3.   TODO = 'TODO'
  4.   DONE = 'DONE'
  5.   DOING = 'DOING' 
  6.  
  7. function todos (status: TODO_STATUS): Todo[]; 
  8.  
  9. 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.   "typescript.tsdk""node_modules/typescript/lib" 

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

延伸 · 阅读

精彩推荐