【你应该掌握的】深刻浅出typescript

团队:skFeTeam  本文做者:高扬css

介绍

TypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。html

TypeScript能够解决JavaScript弱类型和没有命名空间,难以模块化的问题,同时也加强了代码的可读性,在团队协做和大型项目中体现出更大的优点。前端

本文将从“基础用法、高阶用法、模块、react项目实践中的应用”四个方向展开文章,方便你们理解,都会备注列子、codesandbox上的远程代码。react

基础用法

1.变量类型

代码示例 src/components/baseVar.tsxgit

  • TypeScript提供与JavaScript几乎相同的数据类型(布尔值boolean,字符串string,数字number,数组[],元组),此外还提供了枚举enum类型。
  • 当不肯定变量的数据类型或者数据类型会在代码运行过程当中变化时,使用any来标记这些变量,使它们经过编译阶段的检查。
  • object表示原始类型之外的类型,即number,string,boolean,symbol,null,undefined之外的类型。
  • void用于表示没有任何类型,一般用于方法没有返回值时。void类型的变量只能赋值undefined或者null。
  • nullundefined各自的类型分别为null和undefined,并无太大用处。
  • never表示永不存在的类型或方法没法达到终点,当代码中抛出异常或者while(true)时可能会用到。
  • symbol(自ECMAScript 2015起的新的原生类型),不可改变且惟一,经过Symbol函数构造。TypeScript中内置了一些symbols表示语言内部行为。
  • 类型断言: as / <> / !
    当TypeScript没法推断出对象类型但开发者能够肯定时,能够经过类型断言来显式表达变量类型。

在实际使用过程当中,原始类型和any以及类型断言较为经常使用,object,void,null,undefined,never,symbol不常用。github

经常使用的变量类型及声明

2.接口

代码示例 src/components/interface.tsxtypescript

相较于基础类型而言,接口用于更具体地声明更加复杂的对象结构,关键字为interface编程

声明方法

声明方法代码示例1
声明方法代码示例2
方法体内的入参 名称不要求与接口声明中 彻底一致

声明变量

声明变量代码示例
变量声明中:

  • readonly关键字表示属性只读,不可修改。
  • ?表示可选属性,便可以不传该字段,可选参数在必传参数后面。
  • [propName: string]:any能够匹配到除前面已声明属性外的全部字符串名称的属性,如:sex: boolean, address: any, email: string等,可用于不肯定入参中是否还包含其余属性时。

方法的属性排序不要求与接口声明彻底一致数组

设置默认值

默认值代码示例
默认值属于可选参数的一种,但默认值不要求在必选参数以后。
当默认值在可选参数前时,须要传入undefined来获取默认值。

剩余参数

当方法中传参数量不必定或须要批量操做入参时,能够经过剩余参数来操做多个参数。 编程语言

剩余参数代码示例

3.简单的高级类型

代码示例 src/components/types.tsx

交叉类型(&)

交叉类型是将多个类型合并为一个类型,包含全部所需类型的全部属性。

交叉类型代码示例

联合类型(|)

联合类型表示一个值能够是几个类型之一。

联合类型代码示例1
若是一个值是联合类型,咱们 只能访问全部类型的共有成员
联合类型代码示例2

字符串/数字字面量类型

字符串字面量类型容许指定字符串类型的固定值。
数字字面量类型容许指定数字类型的固定值。

字面量类型代码示例

4.迭代器

代码示例 src/components/for.tsx
由于一些内置的类型Map,Array等实现了各自的Symbol.iterator,所以他们都是可迭代的。 (Symbol.iterator方法,被for-of语句调用。返回对象的默认迭代器)
如下语句可用于遍历可迭代对象。

for...of...

(当生成目标为ES5或ES3,迭代器只容许在Array类型上使用。 在非数组值上使用 for..of语句会获得一个错误,就算这些非数组值已经实现了Symbol.iterator属性。)

for-of代码示例

for...in...

for-in代码示例

高阶用法

1.泛型

代码示例 src/components/identity.tsx
泛型,指不预先肯定的数据类型,在使用时才去肯定。这里的使用时,不是指代码运行时。

泛型的本质是将类型参数化,这种参数化的类型可使用在类、接口及方法中成为泛型类、泛型接口、泛型方法。

泛型是用于建立可复用代码组件的重要工具,使得代码片断能够被多种数据类型使用。

考虑当一个方法有多种可能类型的入参,或者一个变量有多种可能类型的赋值时,经过联合类型列出全部可能的类型有时候是不现实或者繁杂的。固然,咱们也能够将其定义为any类型来经过编译阶段的检查,但带来的问题是类型准确性的丢失,调试时也没法看到完整的参数信息。正是所以,TypeScript并不推荐使用any,由于使用any与不引入TypeScript是没有太大区别的。

泛型可用于解决这类问题。

书写泛型接口或方法或类时,咱们经过一个类型变量来捕获参数的类型,显示在**尖括号<>**中,命名随意,一般以大写字母表明

在实际调用该方法时,给类型变量赋予实际的类型,如string,array,number,boolean等;如不赋值具体类型,则TypeScript经过类型推断来检查代码。

泛型代码示例
在示例代码中,func1,func2,func3返回与入参类型一致的出参。< T > < U >捕获入参的类型,并用于规范方法的出参。

泛型约束

有时,咱们对方法的入参虽然不限制类型,但仍然指望他具有某个属性或者知足某些限制,此时咱们可使用extends关键字继承接口来给泛型增长约束。

泛型约束代码示例
示例中func4与func5的区别在于,func5中T extends Leng。当给T增长了约束必须具有length属性时,arg就被限制了类型不能够是number,而且arg.length也不存在undefined的状况。

2.复杂的高级类型

区分类型

代码示例 src/components/types.tsx
当出现**联合类型(Person | Worker)**时,有时咱们须要调用非共有属性,此时须要进一步确认当前变量究竟属于哪一个类型。TypeScript提供了一些方法进行类型区分。

  • typeof / instanceof
    typeof与instanceof能够被TypeScript识别为原始类型的类型保护,咱们能够借此进行原始类型的区分。
    typeof代码示例
  • 用户自定义的类型保护
    当须要对非原始类型进行判断时,用户能够自定义一个类型保护函数,返回值是一个类型谓词,类型谓词形式为paramName is TypeName

用户自定义类型保护代码示例
该示例中 isWorker就是一个类型保护函数,用于判断入参是不是Worker类型,类型谓词是 p is Worker

  • 类型断言
    若是开发人员肯定当前变量在上下文是什么类型,也能够经过类型断言as/<>显式代表当前变量类型来经过TypeScript的检查。

类型断言类型保护代码示例
在实际开发需求中,咱们也常常会遇到某些参数或变量可能为null/undefined的状况,此时调用某些方法就会产生报错。

咱们可使用类型断言标记!后缀手动去除null和undefined。

去除null代码示例

类型别名(Type)

代码示例 src/components/types.tsx

类型别名会给类型(包括原始类型)起一个新的名字。给原始类型取别名能够加强代码可读性,相似于文档,但较少使用。类型别名更多地使用于非原始类型的状况。

类型别名(type)与接口(interface)很是类似,但存在如下几点区别:

  • 接口建立了新的名字,但类型实际上没有
  • 接口能够被extends和implements,但类型不支持
  • 若是须要使用联合类型或交叉类型,这时会选择类型别名
    类型别名代码示例

可辨识联合

代码示例 src/components/union.tsx

可辨识联合也称标签联合或代数数据类型。它是将单例类型,联合类型,类型保护和类型别名合并起来建立的,具备如下三个特征:

  • 具备普通的单例类型属性 - 是该数据类型可辨识的特征
  • 一个数据类型包含了多种类型的联合
  • 该属性上的类型保护 (能够经过单例类型属性进行类型区分)

(单例类型即只有一个实例的类型,可看做是仅有一个值的字符串/数字字面量类型)

可辨识联合代码示例

索引类型

代码示例 src/demos/tk.tsx

使用索引类型,TypeScript能够检查使用了动态属性名的代码。一般用于对象的不常规处理。

索引类型查询操做符keyof能够获取对象上全部属性名,**索引访问操做符K[T]**能够获取对象上特定属性的类型。

索引类型代码示例
在示例代码中,因为K extends keyof T,所以K的取值是有限的,等价于K : "id" | "age" | "school" | "location",而且K的取值随着T的key变化而变化。

映射类型

代码示例 src/demos/tk.tsx

映射类型是TypeScript提供的一种以相同方式从旧的类型中转换出新的类型的方式,例如将全部属性转换为只读属性或可选属性。

TypeScript集成了一些已实现的映射类型。

映射类型代码示例
固然开发者也能够根据业务需求利用索引类型等方式实现自定义的映射类型。

3.模块

代码示例 src/module/*

从ECMAScript 2015开始,JavaScript引入了模块的概念。TypeScript也沿用这个概念。

导出

任何声明(好比变量,函数,类,类型别名或接口)、语句都可以经过添加export关键字来导出。

导出时能够经过as关键字来重命名。

导出代码示例
当一个模块包含多个模块时,能够经过export *来导出全部模块。

导出全部模块代码示例
默认导出

每一个模块均可以有至多一个默认导出,用export default来标记。

导入

使用import关键字导入其余模块中导出的内容,使用as关键字重命名,使用*导入路径下全部导出内容。

导入代码示例
当导入默认导出的模块时,导入时能够自由命名。

默认导入代码示例

直接import "xxx"也是一种导入方式,可是有反作用的导入。导入文件会对整个项目生效,须要谨慎使用。一般仅在项目入口文件里导入全局css时会用到。

相对导入和非相对导入

根据模块引用是相对的仍是非相对的,TypeScript会以不一样的方式解析导入模块。

以/,./或../开头的被认为是相对导入。 例如:

  • import Entry from "./components/Entry";
  • import { DefaultHeaders } from "../constants/http";
  • import "/mod";

全部其它形式的导入都被看成非相对导入。 例如:

  • import { Component } from "@angular/core";

export = 和 import module = require()

为了支持CommonJS和AMD中的exports,TypeScript提供了export = 的导入声明。

当使用export =导出模块时,必需要使用import moduleName = require("xxxx")来导入。

现有React + Antd前端项目中经常使用的一些TS

1.Form表单

代码示例 src/template/form.tsx

form表单

2.Table表格

代码示例 src/template/table.tsx

table表格

参考文章

想了解skFeTeam更多的分享文章,能够点这里,谢谢~

相关文章
相关标签/搜索