最近工作上接触到了很多项目遇到了用了TypeScript,所以需要恶补一下子
使用环境
ts安装
在安装了node环境下, npm install typescript -i
安装完成后, tsc -v 可查看tsc的编译版本,tsc是用了将ts文件编译成js文件的
常用的编译选项
--outDir
指定编译文件输出目录
语法:tsc --outDir 输出目录路径 待编译的文件路径
--target
指定编译的代码版本目标,默认为ES3
语法:tsc --outDir 输出目录路径 --target ES6 待编译的文件路径
--watch
在监听模式下运行,当文件发生改变的时候自动编译
语法:tsc --outDir 输出目录路径 --target ES6 待编译的文件路径
以上是在终端输入的命令行,但我们可以在项目中配置一个tsconfig.json文件,该文件就是将编译选项保存起来统一配置,就不用在命令行中输入一长串的配置命令了
编译配置文件
{
// 编译配置选项
"compilerOptions": {
"outDir":"./dist", // 输出目录
"target": "esnext", // 指定编译出来代码的版本
"watch": true, // 当文件发生改变的时候自动编译
},
"include": ["src/**/*.ts"], // 编译指定文件 *号表示所有
"references": [{ "path": "./tsconfig.node.json" }]
}
在终端中执行 tsc 的时候 就会自动找到当前目录下中的tsconfig.json 执行
或者指定加载配置文件:tsc -p 或者 --project 文件目录
具体内容
类型系统
类型系统包含两个组成部分:类型注解(定义,标注),类型检测(检查) 类型注解:就是在代码中给变量,函数或者函数的参数返回值啥的 添加类型说明,如果说当开发者在coding阶段实际上编辑器就会提示变量,函数等需要遵循什么样的类型去编码 类型检测:就是对开发者不遵循类型注解去开发的时候,进行检测并反馈出来
类型标注
基本的语法格式为: 数据载体:类型
基础的简单类型标注
- 基础类型
-
string
-
number
-
boolean
let name: string = 'xxx'; let age: number = 18; let isMan: boolean = true;
-
- 空和未定义类型
-
null
-
undefined
let a: null; a = null; //这是合理的赋值 a = 1; // 这会提示错误 // undefined也是如此 // 但是注意了 let a: number; a = null; // 这是可以的(可运行) 但是不合理 // 就是说 null与undefined 是所有类型的子类型 // 上述不合理的情况下就是 a如果调用number的方法就会报错 // 所以这怎么规避呢 可以在配置文件中加入 strictNUllChecks 可以有效的检测null或者undefined 避免这些问题
-
- 对象类型
-
js中有很多内置对象,Object,Array,Date等,所以可以通过对像的构造函数或类来进行注解
let obj: object = {}; let arr: Array<number> = [1,2,3]; let strArr: Array<string> = ['x','s','s']; let date: Date = new Date(); -
自定义对象
// 在需要自定义结构对象的时候就需要可以进行以下三种方式 // 字面量标注 —— 优点:方便直接 缺点: 不利于复用和维护 let obj: {username: string, age: number} = {username:'xxx', age = 18}; obj.sex // 报错 // 接口: interface 是定义接口的关键字 // 优点: 复用性高想用就可以直接用 缺点:因为是抽象的结构定义,不是实体,没有具体功能实现的 interface Person { username: string; age: number; }; let obj2: Persion = {username: 'xxx', age: 18}; obj2.sex // 报错 // 定义类或者构造函数 // 优点: 功能相对强大, 定义实体的同时也定义了对应的类型 // 复杂: 复杂,如果只是想约束某个函数接收的参数结构, 并不在意实体的话,实际上没有必要定一个类,使用接口即可 class Person2 { constructor(public username:string, public age:number){} } let user: Person2 = new Person2('xxx',18);
-
- 数组类型
- 使用范型注解
let arr: Array<number> = [] - 简单标注
let arr: sting[] = []
- 使用范型注解
- 元组类型
- 元组类似数组,但是存储的元素类型不必相同
let arr: [string, number] = ['xxx', 18]; -
这里前两个元素必须满足对应向标的类型,后续添加的元素满足定义类型中其中之一即可
- 元组类似数组,但是存储的元素类型不必相同
- 枚举类型
-
枚举的作用组织收集一组相关联数据的方式,通过枚举我们可以给一组有关联意义的数据赋予一些友好的名字
// enum 关键字 enum HTTP_CODE { OK = 200, NOT_FOUND = 404, METHOD_NOT_ALLOWED } HTTP_CODE.METHOD_NOT_ALLOWED; // 405 HTTP_CODE.OK = 1; // 报错 // key不能是数字 // values 可以是数字,称为数字类型枚举,也可以是字符串,称为字符串类型枚举,但不能是其他值默认为数字:0 // 枚举值可以省略,如果是第一个元素 则默认为0,非第一个则在上一个加一 // 字符串类型枚举,枚举类型的值也可以是字符串类型 enum URLS{ USER_LOGIN = '/user/login', USER_index = '/user/index', // 如果前一个枚举值类型为字符串,则后续枚举项必须手动赋值 }
-
- 无值类型
- 表示没有任何数据的类型,通常用于标注无返回值函数的返回值类型,函数默认标注类型为:viod
- 在strictNUllChecks 为 false的情况下,undefined喝null都可以赋值给void,但是当为true的情况下只有undefined才可以赋值给void
- Never类型
- 当一个函数永远不可能执行return的时候 返回的就是never 与viod不同,viod是执行了return,只是 没有值,never是不会执行renturn,比如抛出错误导致函数终止执行
- 任意类型
- 在不确定这个值到底是什么类型的时候或者不需要对该值进行类型检测就可以标注为any类型
- 未知类型
- unknow 3.0版本中新增,属于安全版的any
- unknow 仅能赋值给unknow,any
- unknow 没有任何属性和方法
接口定义
TS的核心之一就是对数据所具有的结构进行类型检查,前面说到了基本类型标注,这里还可以通过interface(接口),来进行标注
接口就是对复杂对象类型进行标注的一种方式,或者给其它代码定义一种契约
基础语法
interface XXX {
readonly x: string; // 表示该字段只读
y: string;
color?: string; // 表示可选
[prop: number]: number; // 表示可添加属性, prop定义只能是数字与字符串类型
}
let persion: XXX = {
x: 'sali',
y: 'aq'
}
使用接口描述函数
interface IFunc {
(a: string):string
}
let fn: IFunc = function(x:string){ return x};
接口合并
如果有多个同名的接口那么会合并成一个接口
interface Box {
a: string;
b: string;
}
interface Box {
c: string;
}
// 最终Box接口里 有abc
高级类型
联合类型
联合类型也可以称为多选类型,当我们希望标注一个变量为多个类型之一时可以选择联合类型标注,或 的关系
function css(ele: Element, attar: string, value: string|number){}
交叉类型
交叉类型也可以称为合并类型,可以把多种类型合并到一起成为一种新的类型,并且 的关系
interface o1 {
x: number;
y: string;
}
interface o2 {
z: number;
}
let o: o1 & o2 = {
x: 1,
y: '22',
z: 100
}
字面量类型
function setPosition(ele: Element, direction: 'left' | 'top' | 'right' | 'bottom'){}
// 由于方向这种特殊的参数 只有固定的值,所以可以用字面量类型配合联合类型进行定义使用
类型别名
关键字 type
type dir = 'left' | 'top' | 'right' | 'bottom'
function setPosition(ele: Element, direction: dir){}
// 有时候类型标注比较复杂时,可用别名进行简化
interface 与 type 的区别
interface
- 只能描述Object/class/function的类型
- 同名interface自动合并,利于扩展 type
- 不能重名
- 能描述所有数据
类型推导
TS编译器会根据当前上下文自动的推导出对应的类型标注,这个过程发生在:
- 初始化变量
- 设置函数默认参数值
- 返回函数值
类型断言
在标注一个更加精确的类型中 比如
let img = document.querySelector('#img');
这里img的类型为Element,Element是知识元素类型的通用类型,那这里去访问src属性时就会有问题,所以需要标注的更加精确,用HTMLImageElement类型,这个时候就可以使用类型断言,类似于一种类型转换,但并非真的转换了
let img = <HTMLImageElement>document.querySelector('#img')