该笔记适合对ts已有过基本了解的小伙伴:
基础知识
boolean、number、string类型声明:
使用类型声明可以帮助我们提前发现代码中赋值与定义不一致的错误。
1 | //boolean |
undefined和null类型:
1 | let u : undefined = undefined |
默认情况下null与undefined是所有类型的子类型,即可以把null与undefined赋值给其他类型的变量。
any、unknown、void类型:
使用场景:
- any类型:不清楚什么类型,可以使用any类型,这些值可能来自于动态的内容(不建议使用)
- unknown类型:代表任何类型,与unknown不同的是它是一个安全类型,它会拦截潜在的风险,如下:
1 | function fn(param:unknown){ |
由于不知道param的类型使用/运算符所以会报错,可以配合类型断言解决问题。
1 | function fn(param:unknown){ |
- void类型:表示没有任何类型,比如函数没有明确返回值,默认使用void类型。
never类型:
never类型表示的是永不存在值的值的类型,即使是any类型也不可以赋值给never类型。
1 | //一个函数抛出异常那么这个函数永远不存在返回值,因为抛出异常会直接中断程序运行 |
数组类型:
1 | let arr : number[] = [1,2,3] |
元组类型:
1 | let arr : [number,string] = [21,"CZH"] |
可以对元组使用数组的方法,不会有越界报错,但是push一个没有定义的类型会报错。
1 | let arr : [number,string] = [21,"CZH"] |
函数类型:
ts定义函数类型需要定义输入参数类型和输出类型,输出类型可以忽略,ts能够根据返回语句自动推断出返回值类型。
1 | function fn(x:number,y:number):number{ |
注意:可选参数要放在函数入参之后,不然会编译错误。
默认参数:
默认参数可以不放在函数入参后面,如果带默认值的参数不是最后一个参数,用户必须明确传入undefined值来获得默认值,不然会报错。
1 | function fn(y:number=100,x:number){ |
函数赋值:
将一个函数赋值给一个变量,可以直接赋值,ts会在变量赋值的过程中自动推断类型:
1 | let add2 = (x: number, y: number): number => { |
函数重载:
函数重载是指两个函数名称相同,但是参数个数或者参数类型不同,不需要将相似功能的函数拆分为多个函数名称不同的函数。
1 | function fn(x:number[]):number |
interface:
接口时用于定义对象类型的可以对对象形状进行描述。
1 | //定义接口一般首字母大写,创建变量的时候属性必须和类型定义的时候完全一致,否则会报错 |
可选属性:
1 | //跟函数可选参数一样,使用?表示可选属性 |
只读属性:
1 | //使用readonly表示属性只读,当初始化之后再次更改会报错 |
interface描述函数类型:
1 | interface Isum { |
自定义属性(可索引的类型):
1 | interface a { |
类
基本写法:
1 | class Person { |
继承:使用extends实现继承,继承之后student类上的实例可以访问Person类上的属性和方法。
1 | class Students Person { |
super关键字:
1 | class Students Person { |
像上图所示如果在student类中有自己的属性,就要用到super关键字将父类的属性继承过来。
public:
在类中用默认所有的方法与属性都是公开的,可写可不写。
private:
用private声明私有属性,只属于类自己,它的实例和继承它的子类都访问不到。
protected:
用protected声明的属性是受保护的,继承它的子类可以访问,实例不能访问。
static:
静态属性,可以理解为类上的一些常量,实例和子类都不能访问。
抽象类:
抽象类是指只能被继承,但是不能被实例化的类。它的特点是:不能被实例化而且抽象类中的抽象方法必须被子类实现。
1 | abstract class Animal { |
抽象类的好处就是可以抽离出事物的共性,有利于代码的复用。
抽象方法与多态:
多态是指父类定义一个抽象方法,在多个子类中有不同的实现,运行的时候不同的子类可以对应不同的操作。
1 | abstract class Animal { |
this类型:
1 | class Step{ |
通过在类的成员方法中直接返回一个this,这样就可以很方便的实现链式调用
在继承的时候,this可以表示父类也可以表示子类,可以灵活调用子类父类的方法。
interface和class的关系:
interface可以用来约束class,要实现约束,需要用到implements关键字
1 | interface exam { |
定义约束之后,class必须满足接口上的所有条件。使用interface来约束class没有继承那么多的条条框框,非常灵活。
约束构造函数和静态属性:
1 | interface CicleStatic { |
枚举
基本使用:
1 | enum Direction { |
反向映射:枚举会对枚举值到枚举名进行反向映射
1 | console.log(Direction[0]) //up |
手动赋值:
1 | enum Direction { |
计算成员:枚举中的成员可以被计算,比如使用位运算合并权限(效率高的位运算符如何使用? - 掘金 (juejin.cn)):
1 | enum FileAccess { |
字符串枚举:提供有具体语义的字符串,可以更容易的理解代码和调试
常量枚举:使用const来定义一个常量枚举
1 | const enum Direction { |
常量枚举可以避免在额外生成的代码上的额外开销和额外的非直接的对枚举成员的访问。
类型推论
在ts中,在没有明确指出类型的地方,类型推论会帮助提供类型,这种推断发生在初始化变量和成员,设置默认参数值和决定函数返回值时。
定义时不赋值:
1 | let a |
定义时不赋值,会被自动推断为any类型。
初始化变量:
1 | let a = "nihao" |
在赋值的时候是一个字符串,所以TS自动推导出a类型是字符串,这个时候如果更改a类型为number类型会报错。
设置默认参数值:
函数设置默认参数时,也会有自动推导。
1 | function fn(num = 18){ |
决定函数返回值:
1 | //当函数不写返回值时自动推导返回值是void类型 |
内置类型
JS八种内置类型:
1 | let name: string = "lin"; |
ECMAScript的内置对象:比如数组、日期或者是正则
1 | const nums : Array<nunmber> = [1,2,3,4] |
DOM和BOM:比如HTML元素、NodeList、鼠标事件等
1 | let body : HTMLElement = document.body |
进阶知识
联合类型
1 | //使用|可以使变量同时支持多种类型 |
联合类型提高了类型的可扩展性但是当TS不确定一个联合类型的变量是哪个类型的时候只能访问他们共有的属性和方法。
交叉类型
使用&可对对象类型进行扩展:
1 | interface Person { |
类型别名
类型别名使用type书写,相当于给类型起一个新名字。跟接口的区别就是类型别名可以作用于原始值,联合类型,元组以及其他任何需要手写的类型。
type与interface的区别:
共同点:
- 都可以定义一个对象或者函数
- 都允许继承
不同点:
- interface是ts设计出来用于定义对象类型的,可以对对象的形状进行描述
- type是类型别名,用于给各种类型定义别名,让ts写起来更简洁、清晰
- type可以声明基本类型、联合类型、元组,但是interface不行
- interface可以合并重复声明,type不行
平时开发中,一般使用组合或者交叉类型的时候,使用type;一般要用类的extends或implements时用interface
合并重复声明:
1 | interface Person { |
如果换成是type,就会报错。
1 | type Person = { |
类型保护
1 | function fn(age:number|string):number{ |
类型断言
上面的例子也可以使用类型断言解决:
1 | function fn(age:number|string):number{ |
注意:类型断言不是类型转换,把一个类型断言成联合类型中不存在的类型会报错。
字面量类型
1 | type sex = "男" | "女" |
这样定义就只能从定义的常量中取值,乱取值会报错。
泛型
泛型的语法是<>里写类型参数,一般可以用T表示。
1 | function print<T>(arg:T):T { |
我们在使用的时候可以有两种方式指定类型:
1、定义要使用的类型
2、TS类型推断,自动推导出类型
1 | print<string>("hello") //定义T为string |
type与interface也可以定义泛型:
1 | type Print = <T>(arg:T) => T |
1 | interface Print<T> { |
默认参数:
1 | interface Print<T = number> { |
索引类型
keyof(索引查询):keyof操作符可以用于获取某种类型的所有键,其返回值是联合类型。
1 | interface Person { |
T[k](索引访问):表示接口T的属性K所代表的类型
1 | interface Person { |
extends(泛型约束):T extends U表示泛型变量可以通过继承某个类型,获得某些属性
1 | interface Person { |
映射类型
TS允许将一个类型映射成另一个类型。
in:用于对联合类型实现遍历。
1 | type Person = "name" | "age" | "sex" |
Partial<T>:将T所有的属性映射为可选的。
1 | interface Person { |
Readonly:Readonly<T>将T的所有属性映射为只读的
Pick:Pick映射类型有两个参数:①T:表示要抽取的对象②K:具有一个约束,K一定要来自T所有属性字面量的联合类型
1 | interface Person { |
Record:可以创建新属性的非同态映射类型
1 | interface Person { |