typescript常见高级技巧总结

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

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

01 keyof

keyofObject.keys 略有相似,只不过 keyofinterface 的键。

interface Point {
    x: number;
    y: number;
}

// type keys = "x" | "y"
type keys = keyof Point;

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

const data = {
  a: 3,
  hello: 'world'
}

function get(o: object, name: string) {
  return o[name]
}

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

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

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

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

02 Required & Partial & Pick

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

type Partial<T> = {
  [P in keyof T]?: T[P];
};

type Required<T> = {
  [P in keyof T]-?: T[P];
};

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

interface User {
  id: number;
  age: number;
  name: string;
};

// 相当于: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial<User>

// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">

这几个类型已内置在 Typescript 中

03 Condition Type

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

T extends U ? X : Y

type isTrue<T> = T extends true ? true : false
// 相当于 type t = false
type t = isTrue<number>

// 相当于 type t = false
type t1 = isTrue<false>

04 never & Exclude & Omit

官方文档对 never 的描述如下

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

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

type Exclude<T, U> = T extends U ? never : T;

// 相当于: type A = 'a'
type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'>

结合 Exclude 可以推出 Omit 的写法

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

interface User {
  id: number;
  age: number;
  name: string;
};

// 相当于: type PickUser = { age: number; name: string; }
type OmitUser = Omit<User, "id">

05 typeof

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

const a: number = 3

// 相当于: const b: number = 4
const b: typeof a = 4

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

import logger from './logger'
import utils from './utils'

interface Context extends KoaContect {
  logger: typeof logger,
  utils: typeof utils
}

app.use((ctx: Context) => {
  ctx.logger.info('hello, world')

  // 会报错,因为 logger.ts 中没有暴露此方法,可以最大限度的避免拼写错误
  ctx.loger.info('hello, world')
})

06 is

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

app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    let code = 'BAD_REQUEST'
    if (err.isAxiosError) {
      code = `Axios-${err.code}`
    } else if (err instanceof Sequelize.BaseError) {

    }
    ctx.body = {
      code
    }
  }
})

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

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

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

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

function isAxiosError (error: any): error is AxiosError {
  return error.isAxiosError
}

if (isAxiosError(err)) {
  code = `Axios-${err.code}`
}

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

export function isType(type: any): type is GraphQLType;

export function isScalarType(type: any): type is GraphQLScalarType;

export function isObjectType(type: any): type is GraphQLObjectType;

export function isInterfaceType(type: any): type is GraphQLInterfaceType;

07 interface & type

interfacetype 的区别是什么?可以参考以下 stackoverflow 的问题

stackoverflow.com/questions/3…

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

interface A {
  a: number;
  b: number;
};

type B = {
  a: number;
  b: number;
}

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

interface A {
    a: number;
}

interface A {
    b: number;
}

const a: A = {
    a: 3,
    b: 4
}

08 Record & Dictionary & Many

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

type Record<K extends keyof any, T> = {
    [P in K]: T;
};

interface Dictionary<T> {
  [index: string]: T;
};

interface NumericDictionary<T> {
  [index: number]: T;
};

const data:Dictionary<number> = {
  a: 3,
  b: 4
}

09 使用 const enum 维护常量表

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

// 使用 object 维护常量
const TODO_STATUS {
  TODO: 'TODO',
  DONE: 'DONE',
  DOING: 'DOING'
}
// 使用 const enum 维护常量
const enum TODO_STATUS {
  TODO = 'TODO',
  DONE = 'DONE',
  DOING = 'DOING'
}

function todos (status: TODO_STATUS): Todo[];

todos(TODO_STATUS.TODO)

10 VS Code Tips & Typescript Command

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

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

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

{
  "typescript.tsdk": "node_modules/typescript/lib"
}

11 Typescript Roadmap

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

(0)

相关推荐

  • Typescript协变与逆变简单理解

    目录 1. 协变和逆变简单理解 2. 协变举例 3. 逆变举例 4. 更简单点的理解 5. 参考 1. 协变和逆变简单理解 先简单说下协变和逆变的理解. 首先,无论协变还是逆变,必然是存在于有继承关系的类当中,这个应该好理解吧.如果你只有一个类,那没有什么好变的. 其次,无论协变还是逆变,既然是变,那必然是存在不同类之间的对象的赋值,比如子类对象赋值给父类对象,父类对象赋值给子类对象,这样才叫做变. 结合上面两条,我觉得协变和逆变在我的字典中就能定义成:支持子类对象赋值给父类对象的情况称之为协变

  • 关于TypeScript声明合并

    目录 介绍 基础概念 合并接口 合并命名空间 命名空间与类和函数和枚举类型合并 合并命名空间和类 非法的合并 模块扩展 全局扩展 介绍 TypeScript中有些独特的概念可以在类型层面上描述JavaScript对象的模型. 这其中尤其独特的一个例子是“声明合并”的概念. 理解了这个概念,将有助于操作现有的JavaScript代码. 同时,也会有助于理解更多高级抽象的概念. 对本文件来讲,“声明合并”是指编译器将针对同一个名字的两个独立声明合并为单一声明. 合并后的声明同时拥有原先两个声明的特性

  • typescript常见高级技巧总结

    用了一段时间的 typescript 之后,深感中大型项目中 typescript 的必要性,它能够提前在编译期避免许多 bug,如很恶心的拼写问题.而越来越多的 package 也开始使用 ts,学习 ts 已是势在必行. 以下是我在工作中总结到的比较实用的 typescript 技巧. 01 keyof keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键. interface Point { x: number; y: number; } //

  • TypeScript常见类型及应用示例讲解

    目录 常见类型(Everyday Types) 原始类型: 数组(Array) any noImplicitAny 变量上的类型注解(Type Annotations on Variables) 函数(Function) 参数类型注解(Parameter Type Annotations) 返回值类型注解(Return Type Annotations) 匿名函数(Anonymous Functions) 对象类型(Object Types) 可选属性(Optional Properties)

  • 那些项目中常见的TypeScript错误总结

    目录 引言 1.TS2456 2.TS2554 3.TS1169 4.TS2345 5.TS2589 6.TS2322 总结 引言 TypeScript 错误信息由错误码和详细信息组成.例如:TS2456 ,其中错误码是以“TS”开头 + 数字(一般是 4 位数字)结尾这样的格式组成的字符串,用来作为特定类型错误的专属代号.下面我们看一下那些常⻅,但在官方文档甚少提及的类型错误: 1.TS2456 首先是由于类型别名循环引用了自身造成的 TS2456 类型错误,如下示例: type T = Re

  • React中常见的TypeScript定义实战教程

    目录 一 引沿 二 什么是调和 三 什么是Filber 四 实现调和的过程 五 总结 一 引沿 Fiber 架构是React16中引入的新概念,目的就是解决大型 React 应用卡顿,React在遍历更新每一个节点的时候都不是用的真实DOM,都是采用虚拟DOM,所以可以理解成fiber就是React的虚拟DOM,更新Fiber的过程叫做调和,每一个fiber都可以作为一个执行单元来处理,所以每一个 fiber 可以根据自身的过期时间expirationTime,来判断是否还有空间时间执行更新,如

  • bat命令入门与高级技巧详解

    目录 第一章 批处理基础 第一节 常用批处理内部命令简介 1.REM 和 :: 2.ECHO 和 @ 3.PAUSE 4.ERRORLEVEL 5.TITLE 6.COLOR 7.mode 配置系统设备 8.GOTO 和 : 9.FIND 10.START 11.assoc 和 ftype 12.pushd 和 popd 13.CALL 14.shift 15.IF 16.setlocal 与 变量延迟(ENABLEDELAYEDEXPANSION / DISABLEDELAYEDEXPANSI

  • javascript函数中的3个高级技巧

    前面的话 函数对任何一门语言来说都是一个核心的概念,在javascript中更是如此.前面曾以深入理解函数系列的形式介绍了函数的相关内容,本文将再深入一步,介绍函数的3个高级技巧 技巧一:作用域安全的构造函数 构造函数其实就是一个使用new操作符调用的函数 function Person(name,age,job){ this.name=name; this.age=age; this.job=job; } var person=new Person('match',28,'Software E

  • TypeScript Type Innference(类型判断)

    TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeScript与JavaScript相比进步的地方 包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销:增加一个完整的类结构,使之更新是传统的面向对象语言. 为什么会有 TypeScript? JavaScript 只是一个脚本语言,并非设计用于开发大型 Web 应用,JavaScript 没有提供类和模块的概

  • 深入理解JavaScript和TypeScript中的class

    前言 对于一个前端开发者来说,很少用到 class ,因为在 JavaScript 中更多的是 函数式 编程,抬手就是一个 function,几乎不见 class 或 new 的踪影.所以 设计模式 也是大多数前端开发者的一个短板. 最近在学习 Angular的过程中发现其大量的运用了 class,不得不佩服,Angular 确实是一个优秀的.值得深入研究的 框架. 本文将简单的介绍一下 JavaScript 和 TypeScript 中的 class. 基本概念 在介绍 class 之前,要先

  • vue-cli3+typescript新建一个项目的思路分析

    最近在用vue搭一个后台管理的单页应用的demo,因为之前只用过vue-cli2+javascript进行开发,而vue-cli3早在去年8月就已经发布,并且对于typescript有了很好地支持.所以为了熟悉新技术,我选择使用vue-cli3+typescript进行新应用的开发.这里是新技术的学习记录. 初始化项目 卸载老版本脚手架,安装新版本脚手架后,开始初始化项目.初始化的命令跟2.x版本的略有不同,以前是 vue init webpack project-name ,而现在是 vue

  • 浅谈Vue3.0之前你必须知道的TypeScript实战技巧

    很多人对TypeScript的使用还停留在基本操作上,其实TypeScript的特性非常强大,我们利用好这些特性可以有效地提高代码质量.加速开发效率,今天就介绍9个非常实用的TypeScript技巧或者特性. 注释的妙用 我们可以通过 /** */ 来注释TypeScript的类型,当我们在使用相关类型的时候就会有注释的提示,这个技巧在多人协作开发的时候十分有用,我们绝大部分情况下不用去花时间翻文档或者跳页去看注释. 巧用类型推导 TypeScript 能根据一些简单的规则推断(检查)变量的类型

随机推荐