ts介绍
- js 是动态类型 (已经定义的变量可以更改为另一种类型变量)
- ts 是静态类型,在编译前会转换为 js,在编译阶段会进行类型检查
- ts 是弱类型。类型系统按照[是否允许隐式类型转换]来分类,可分为强类型和弱类型
数据类型
基本类型
声明变量需在变量后写明类型,例如:
let num:number = 0
- 基础类型:string、number、boolean、void、undefined、null、symbol
- 对象类型:{}、Class、function、[]
string 类型
- 字符串字面量类型:当把一个变量指定为这个字符串类型时,就不能再赋值为其他字符串值
let str: 'cen'
str = 'auto' // --> 不能将类型“"auto"”分配给类型“"cen"”
boolean 类型
- 在 ts 中,boolean 类型的值除只能是
true
和false
外,还能是计算结果为布尔值的表达式 - 使用构造函数
Boolean
创建的对象不是布尔值
void类型
表示没有任意类型
- 使用场景
- 函数没有返回值
undefined
null 和 undefined 类型
- 定义为 null 或 undefined 类型的,赋值可以为 null 和 undefined 其中之一
- null 和 undefined 是所有类型的子类,可以赋值给其他类型变量
let un: undefined = undefined;
let num: number = un;
object 类型
- 包含Object 和 {}类型
- 该类型用于表示非原始类型
- 该类型是所有 Object 类的实例的类型
- {}类型描述一个没有成员的对象
类型注解和类型推断
- type annotation 类型注解:告诉 TS 变量是什么类型
const num: number = 123;
- type inference 类型推断:TS 会自动区尝试分析变量类型
const num = 123;
- 一般声明变量并赋值的情况下不需要类型注解,而遇到函数参数时需要类型注解
- 为代码更严谨,返回值建议也加上类型注解
function getnum(num1: number, num2: number): number {
return num1 + num2;
}
const total = getnum(1, 2);
其他类型
unknown 未知类型
- 与
any
一样,可以是任意类型 - 是
any
类型对应的安全类型 unknown
与any
的区别:unknown
会更加严格,在对unknown
类型的值执行大多数操作之前,会对其进行某种形式的检查;而any
不会进行检查unknown
是any
更好的替代品
never
- 两个场景never比较常见
- 抛出异常的函数永远不会有返回值
- 空数组:且永远是空的
const empty: never[] = []
元祖 tuple
表示一个已知元素数量和类型的数组,各元素类型不必相同
- 各个位置上的元素类型都要对应,元数个数也一致
- 严格按照定义的元素类型编译,元素顺序 与 定义的元素类型须一一对应
- 元祖越界问题:ts允许元祖使用数组的push()方法添加新元素。添加时会正常运行,但当访问添加的元素时会报错
- 当访问一个越界的元素,会使用联合类型来替代
tuple1.push(6) // ok
console.log(tuple1[2]); // Tuple type '[string, number]' of length '2' has no element at index '2'
高级类型
交叉类型
- 多个类型合并成一个类型。属性相同时,如果后一个类型上此属性比前一个类型上的更具体,则会覆盖
- 被
&
连接多个类型构成交叉类型
联合类型
- 用
|
连接 - 符合联合类型中任意一种类型即可
枚举类型
用于一组命名的常数,当一个变量有几种可能的取值时,可以定义为枚举类型
本质上是javascript对象
- 值默认数字类型
数字枚举
- 默认从0开始累加,后面的值以此递增
- 后面的值会在前一个值基础上递增
enum Direction {
top = 10,
right,
bottom,
left
}
console.log(Direction.top, Direction.right, Direction.bottom, Direction.left); // 10 11 12 13
枚举杂记
- 字符串枚举每个成员都需要赋值,否则会报错
- 在ts枚举类型中存在反向映射,即:
name <=> value
。例子:
console.log(Direction[10]) // top
属性检查
类型断言
let mySquare = CalculateAreas({ widdth: 5 } as Config)
// 如上,当传入的widdth属性不存在时,将从Config中查找
function traniAnimal(animal: Bird | Dog) {
if (animal.fly) {
(animal as Bird).sing()
} else {
(animal as Dog).bark()
}
}
字符串索引签名 [propName: string]: any
描述对象索引的类型,还有相应索引的返回值类型
- 例子:
[name: string]: string
class 类
- 子类继承父类后,子类可以重写父类中的方法 (覆盖)
super
关键字可以调用父类中的属性、方法
类的访问器
get
和set
get name() {
return this._name
}
set name(name: string) {
this._name = name
}
抽象类
abstract
关键字定义抽象类和抽象类内部定义抽象方法- 不能直接实例化抽象类,通常需定义子类来继承基类,然后实例化子类
访问限定符
在ts类中,成员都默认为public
- public (公共,内外部可访问)
- private (类的内部)
- protected (类的内部以及子类)
类杂记
- 如果子类中存在 constructor,那么需在子类的 constructor 中需调用 super()
static
定义静态属性、方式,通过类调用;不能通过实例化变量调用- 抽象类(
abstract
)存放一些公共的属性、方法,子类继承
泛型
定义:是一种特殊变量,只用于表示类型而不是值,位置位于函数参数左括号前 – > (
泛型
就像常规函数参数一样,区别在于:常规函数参数处理值,而泛型处理类型参数- 泛型命名:通常取命名单词的首字母,比如常见的有:
T
(forType
)E
(forElement
)K
(forKey
)V
(forValue
)
函数泛型
- 一般适用场景:静态编写代码时不确定传入的参数是什么类型,只有当调用时才确定类型
装饰器
类的装饰器
- 类装饰器本身是函数,接受的参数是
constructor
(构造函数) - 装饰器通过
@
符号使用,当类创建好后立即执行,并不是实例化后执行 - 收集装饰器是从上到下,从左到右;而执行装饰器是从下到上
new (...args: any[]) => {}
通过实例化创建出一个类,类包含new (...args: any[]) => {}
构造函数new
表示是构造函数,args
接受多个参数,类型是any。返回值是对象
方法装饰器
- target
- 普通方法:类的pototype
- 静态方法:类的构造函数
- key对应方法名
- descriptor 表示对方法的descriptor属性做一些编辑
descriptor.writable: false
:不允许修改属性值descriptor.enumerable: false
:即为不可枚举(不被遍历)
function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
// descriptor.writable = false // --> 修饰方法不可被重写
// descriptor.value --> 方法的值
descriptor.value = function() {
return 'descriptor'
}
}
访问器装饰器
- ts不允许同时装饰一个成员的get和set访问器,只需要这个成员get/set访问器中定义在前面一个即可
其他
- 可用void表示没有任何返回值的函数
- 定位一个变量为静态类型,不仅该变量不能被修改为其他类型,而且该变量会具备对应类型的所有属性、方法。
- interface与type区别:interface 可定义对象、数组、函数等类型,而 type 定义的变量不仅可以代表对象,还能是具体类型
type person = {
name: string;
};
type person1 = string;
- 当函数实参以字面量形式传递时,ts 会进行强校验。以变量形式传递则不会
- interface 只会在开发时做校验,不会转换为对应的 js
- Symbol的值是唯一不变的
- 函数
重载
:重载定义了函数几种不同形式的形态,如果不满足上面重载定义的某一种形态,会报错- 同一个函数名字根据函数参数不同而可以定义多个函数
- 使用
namespace
好处:减少全局命名空间,模块化 - 关键字
declare
表示声明全局变量类型
配置
tsconfig.json
outDir
:输出路径
tsc运行原理
- 当命令行上指定了输入文件时,tsconfig.json文件会被忽略(不会按照配置项来编译)
- tsc默认会对项目目录下所有ts文件进行编译,解决方法有以下几种
include
项、files
项指定需要编译的文件exclude
项指定不需要编译的文件
package.json
-D
<=>--save-dev
-->devDependencies
-S
<=>--save
-->dependencies
tsc -w
与nodemon
结合更好实现ts-node
效果
"scripts": {
// `-w` 表示当监视到ts文件发生改变时,自动执行tsc命令
"dev:build": "tsc -w",
// 监视项目文件状态,当变化时执行node ./build/src/crowller.js操作
"dev:run": "nodemon node ./build/src/crowller.js"
}
配置nodemon需要忽略监视的文件
"nodemonConfig": {
"ignore": ["data/*"]
}
插件
nodemon
:能监视文件改变并执行一些操作concurrently
:并行执行命令npm
后第一个:
代表run
"dev": "concurrently npm:dev:*"