前言 TS是JS的超集,TS提供了JS的所有功能,并增加了:类型系统,并且TS会检查并显示标记出代码中的错误。 目标
1 了解并掌握TS的类型注解 2 JS与TS的类型分别有哪些? 3 掌握TS各种类型的使用方法
graph LR
A[TS常用类型] --> B[1 TS类型注解与基础类型概述]
B --> C[类型注解]
B --> D[基础类型概述]
A --> E[2 JS已有类型]
E --> F[原始类型]
E --> G[对象类型:数组,函数:可选参数,对象 ]
A --> H[3 TS新增类型]
H --> I[联合类型,类型别名,接口,元组,字面量类型,枚举,any类型]
H --> J[typeOf运算符]
1 TS类型注解与基础类型概述
1.1 类型注解
示例:
定义变量
a
是number类型
,相当于给变量a加了一个类型的约束
约束了什么类型只能赋值该类型的值,否则就会报错
1.2 基础类型概述
可以将TS中的常用基础类型细分为两类:1 JS已有类型
2 TS新增类型
1 jS已有类型
- 原始类型:number/string/boolean/null/undefined/symbol。
- 对象类型:object(包含:数组、对象、函数等对象)。
2 TS新增类型
- 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、viod、any等。
2 js已有类型
2.1 原始类型
原始类型有:number/string/boolean/null/undefined/symbol。 定义非常简单,按照js类型名小写来定义
let a: number = 1
let b: string = '2'
let c: boolean = true
let d:null = null
let e: undefined = undefined
let f:undefined = undefined
let g:symbol = Symbol()
2.2 对象类型
对象类型:object(包含:数组、对象、函数等对象)。
在TS中,对象类型的更加的细化,每个具体的对象都有自己的类型语法
2.2.1 数组类型
数组类型两种简单写法
方式一
// 数组中参数类型 - number
let num:number[] = [1,2,3]
// 数组中参数类型 - string
let num1:string[] = ['1','2','3']
方式二
// 数组中参数类型 - number
let num1:Array<number> = [1,2,3]
// 数组中参数类型 - string
let num1:Array<string> = ['1','2','3']
2.2.2 函数类型
函数的类型实际上指的是:函数参数
和返回值
的类型
1 函数指定类型的两种方式
为函数指定类型的两种方式:
- 单独指定参数、返回值的类型
- 同时指定参数、返回值的类型
1 单独指定参数、返回值类型
函数返回值类型不是viod
或者any
,必须要有返回值
函数返回值类型是viod
或者any
,可以无返回值
2 同时指定参数、返回值的类型
定义属性add为一个函数类型,函数参数如下
2 可选参数
使用函数实现某个功能时,参数可以传也可以不传。
这种情况下,在给函数参数指定类型时,就用到可选参数
了
比如,数组的slice 方法,可以slice() 也可以 slice(1) 还可以slice(1,3)。
function myslice(a?:number,b?:number):void{
console.log(a,b);
}
myslice()
myslice(1)
myslice(1,2)
可选参数:在可传可不传的参数名称后面添加?
(问号)
注意:可选参数只能出现在参数列表的最后
,也就是说可选参数后面不能再出现必选参数
2.2.3 对象类型
JS中的对象是由属性和方法构成的,而Ts中对象的类型
就是在描述对象的结构
(有什么类型的属性和方法)
对象类型的写法:
- 直接使用{}来描述对象结构。属性采用
属性名:类型
的形式,方法采用方法名():返回值
类型的形式 - 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如:
greet(name:string):void
) - 在一行代码中指定对象的多个属性类型时,使用;(分号)来分隔 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉;(分号)。 方法的类型也可以使用箭头函数形式(比如:sayHi:()=>void])
可选属性 使用方法与数组中的可选属性类似
function getAxios(obj:{name:string;age:number,sex?:string}):void{
}
getAxios({
name:'张三',
age:18
// sex可传可不穿
})
3 TS新增类型
联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、viod、any等。
3.1 联合类型
3.2 类型别名
类型别名
(自定义类型):为任意类型起别名
使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型
的使用
- 使用
type
关键字来创建类型别名。 - 类型别名(比如,此处的CustomArray),可以是任意合法的变量名称。
- 创建类型别名后,直接使用
该类型别名作为变量的类型注解
即可
3.3 接口
当一个对象类型被多次使用时,一般会使用接口 (interface)
来描述对象的类型,达到复用
的目的
解释:
- 使用interface 关键字来声明接口
- 接口名称(比如,此处的IPerson),可以是任意合法的变量名称
- 声明接口后,直接
使用接口名称作为变量的类型
- 因为每一行只有一个属性类型,因此,属性类型后没有;(分号)
interface IPerson {
name:string
age:number
sayHi():void
greet(name:string):void
}
let person:IPerson = {
name:'张三',
age:18,
sayHi(){},
greet(name:string){}
}
interface 接口与type类型别名的对比
- 相同点:都可以给对象指定类型
- 不同点:
接口: 只能为
对象
指定类型 类型别名: 不仅可以为对象指定别名,实际上可以为任何类型
指定别名
接口继承
如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用
。
比如,这两个接口都有x、y两个属性,重复写两次,可以,但很繁琐。
interface P {
a:number
b:string
}
// interface P1 {
// a:number
// b:string
// c:boolean
// }
// p1继承p的所有属性与方法
interface P1 extends P {
c:boolean
}
3.4 元组
场景: 在地图中,使用经纬度坐标来标记位置信息
**数组的缺点:**不严谨,因为该类型的数组中可以出现任意多个数字。
元组 (Tuple)
元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型
let position:[number,number] = [1.2,2.1023]
解释
- 元组类型可以确切地标记出有多少个元素,以及每个元素的类型
- 该示例中,元素有两个元素,每个元素的类型都是number。
补充:(1) 类型推论
在 TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型
换句话说:由于类型推论的存在,这些地方,类型注解可以省略
不写!
发生类型推论的2种常见场景: 1 声明变量并初始化时
2 决定函数返回值时
1 声明变量并初始化时
声明属性a,初始化18 类型推论会自动地推断出,属性a的类型是numver
2 决定函数返回值时
a,b都是number类型,a+b的也是number
类型推论可以得出 函数返回值是number类型
上面这里两种情况,类型注解可以省略不写
推荐: 能省略类型注解的地方就省略
(偷懒,充分利用TS类型推论的能力,提升开发效率)
技巧: 如果不知道类型,可以通过鼠标放在变量名称上,利用VSCode 的提示来查看类型
(2) 类型断言
有时候你会比TS更加明确一个值的类型,此时,可以使用类型断言
来指定更具体的类型
getElementByld
方法返回值的类型是HTMLElement
,该类型只包含所有标签公共的属性或方法
,不包含a标签特有的href等属性。
因此,这个类型太宽泛(不具体),无法操作href等a标特有的属性或方法
这种情况下,就需要使用
类型断言
指定更加具体的类型
使用类型断言
- 使用
as
关键字实现类型断言。 - 关键字as后面的类型是一个更加具体的类型(
HTMLAnchorElement
是HTMLElement的子类型)。 - 通过类型断言,aLink的类型变得更加具体,这样就可以访问a标签特有的属性或方法了另一种语法,
使用
<>
语法,这种语法形式不常用知道即可
// 两种方式实现类型断言
// 方式一:推荐使用
let aLink = document.getElementById('link') as HTMLAnchorElement
// 方式二
let aLink1 = <HTMLAnchorElement>document.getElementById('link')
aLink1.href = 'https://www.baidu.com'```
如何知道标签使用的子类型? 1 记住子类型
标签 | 对应子类型 |
---|---|
div | HTMLDivElement |
a | HTMLAnchorElement |
button | HTMLButtonElement |
.... | 以此类推 |
2 记住子类型
在浏览器控制台,通过
console.dir()
打印 DOM 元素,在属性列表的最后面,即可看到该元素的类型。
当前选中的元素
打印标签的DOM元素
3.5 字面量类型
变量a的类型是 1 ,变量b的类似是 ‘hi’
这里的1 或 ‘hi’ 就是字面量类型
对象、数字、字符串
等都可以作为TS的字面量
类型使用
字面量类型
常与联合类型
一起使用 ==> ==推荐==
使用场景:用来表示一组明确的可选列表
与string相比: 使用字面量更加的精准、严谨
3.6 枚举类型
枚举的功能类似于字面量类型+联合类型组合
的功能,也可以表示一组明确的可选值
枚举: 定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个。
enum Direction{
Up,
Down,
Left,
Right
}
function getDirection(direction:Direction):void{
console.log(direction);
}
// 实参的值 就是枚举类型Direction成员中的一个
getDirection(Direction.Up)
枚举类型
- 1.使用
enum
关键字定义枚举 - 2.约定枚举名称、枚举中的值以
大写字母开头
- 3.枚举中的多个值之间通过,(逗号)分隔
- 4.定义好枚举后,直接使用枚举名称作为类型注解
3.6.1 数字枚举
数字枚举中枚举成员的值,默认从0开始自增
// Up = 0, Down = 1, Left = 2, Right = 3 =》 默认
enum Direction{Up,Down,Left,Right}
// Up = 10, Down = 11, Left = 12, Right = 13
enum Direction{Up = 10,Down,Left,Right}
enum Direction{Up = 10,Down = 20,Left = 30,Right = 10}
3.6.2 字符串枚举
字符串枚举: 枚举成员的值是字符串
没有自增行为,所以,字符串枚举成员必须有初始值
enum Direction{
Up = 'UP',
Down = 'down',
Left = 'LEFT',
Right = 'RIGHT'
}
3.6.3 枚举的特点以及原理
枚举是TS为数不多的非JavaScript类型级扩展(不仅仅是类型)的特性之一。
其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值
(枚举成员都是有值的)也就是说,
其他的类型会在编译为JS代码时自动移除。但是,枚举类型会被编译为JS代码!
可选值列表: 推荐使用
字面量+联合类型
,相比枚举,更加的直观、简介、高效
3.8 any类型
原则上不推荐使用any类型
!这会让TypeScript 变为“AnyScript”(失去TS类型保护的优势)
因为当值的类型为any时,可以对该值进行任意操作,并且不会有代码提示
,即时有错误。
隐式any情况:
- 1 声明变量不提供类型也不提供默认
- 2 函数参数不加类型
3.9 typeof运算符
-
使用
typeof
操作符来获取变量p 的类型,结果与第一种(对象字面量形式的类型)相同。 -
typeof出现在
类型注解的位置
(参数名称的冒号后面)所处的环境就在类型上下文
(区别于JS代码) -
注意:typeof只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)。