1.类型注解
let age: number = 18
代码中 :number 就是类型注解
作用:为变量添加类型约束。比如,上述代码中,约定变量 age 的类型为 number 类型
解释:约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错
// 错误演示
// 错误原因:将 string 类型的值赋值给了 number 类型的变量,类型不一致
let age: number = '18'
2.原始类型
1、JS 已有类型
* 原始类型:`number/string/boolean/null/undefined/symbol`
* 对象类型:`object`(包括,数组、对象、函数等对象)
2、TS 新增类型
* 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等
* 注意:
* *原始类型*在 TS 和 JS 中写法一致
* *对象类型*在 TS 中更加细化,每个具体的对象(比如,数组、对象、函数)都有自己的类型语法
原始类型:
let age: number = 18
let myName: string = '黑马程序员'
let isLoading: boolean = false
let nullValue: null = null
let undefinedValue: undefined = undefined
// 特点:Symbol() 创建的值是唯一的
// 作用:可以作为对象属性的键,防止与对象中其他键冲突
let uniqKey: symbol = Symbol()
let obj = {
a: '123',
[uniqKey]: 100,
}
// 取值:
console.log(obj[uniqKey])
3.数组类型
两种写法:
// 写法一:(推荐)
let numbers: number[] = [1, 3, 5]
// 写法二:
let strings: Array<string> = ['a', 'b', 'c']
4.联合类型
通过联合类型将多个类型组合成一个类型
// 此处 () 的目的是为了将提升优先级,表示:number 类型的数组或 string 类型的数组
let arr: (number | string)[] = [1, 'a', 3, 'b']
- * 解释:`|`(竖线)在 TS 中叫做**联合类型**,即:由两个或多个其他类型组成的类型,表示可以是这些类型中的**任意一种**
- * 注意:这是 TS 中联合类型的语法,**只有一根竖线**,不要与 JS 中的或(|| 或)混淆了
5.类型别名(自定义类型)
使用类型别名给类型起别名
- * 类型别名(自定义类型):为任意类型起别名
- * 使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,**简化该类型的使用
type CustomArray = (number | string)[]
let arr1: CustomArray = [1, 'a', 3, 'b']
let arr2: CustomArray = ['x', 'y', 6, 7]
解释: 1. 使用 `type` 关键字来创建自定义类型
2. 类型别名(比如,此处的 *CustomArray*)可以是任意合法的变量名称
3. 推荐使用大写字母开头
4. 创建类型别名后,直接使用该类型别名作为变量的类型注解即可
6.函数类型----参数和返回值
给函数指定类型
- 函数的类型实际上指的是:`函数参数`和`返回值`的类型
- 为函数指定类型的两种方式:
* 单独指定参数、返回值的类型
* 同时指定参数、返回值的类型
1、单独指定参数、返回值的类型:
// 函数声明
function add(num1: number, num2: number): number {
return num1 + num2
}
// 箭头函数
const add = (num1: number, num2: number): number => {
return num1 + num2
}
2、同时指定参数、返回值的类型:
* 解释:当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型
* 注意:这种形式只适用于函数表达式
// 创建函数自定义类型
type AddFn = (num1: number, num2: number) => number
// 使用自定义类型作为函数 add 的类型
const add: AddFn = (num1, num2) => {
return num1 + num2
}
遇到问题:使用函数自定义类型的时候,使用const,而不是function
函数类型-----void类型
- 如果函数没有返回值,那么,函数返回值类型为:`void`
function greet(name: string): void {
console.log('Hello', name)
}
- 注意:如果一个函数没有返回值,此时,在 TS 的类型中,应该使用 `void` 类型
- 注意:不要与 undefined 类型混淆
// 如果什么都不写,此时,add 函数的返回值类型为: void
const add = () => {}
// 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同
const add = (): void => {}
// 但,如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以
const add = (): undefined => {
// 此处,返回的 undefined 是 JS 中的一个值
return undefined
}
函数类型----可选参数
- 使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到**可选参数**了
function Kexuan(a:number,b?:number) {
if(b){
return a+b
}
return a
}
- 可选参数:在可传可不传的参数名称后面添加 `?`(问号)
- 注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数
7. 对象类型
- JS 中的对象是由属性和方法构成的,而 TS 对象的类型就是在描述对象的结构(有什么类型的属性和方法)
- 对象类型的写法
// 空对象 宽泛的定义,里面是什么都行
let person: {} = {}
// 有属性的对象
let person: { name: string } = {
name: 'cc'
}
// 既有属性又有方法的对象
// 在一行代码中指定对象的多个属性类型时,使用 `;`(分号)来分隔
let person: { name: string; sayHi(name: string): void } = {
name: 'jack',
sayHi(name) {}
}
// 对象中如果有多个类型,可以换行写:
// 通过换行来分隔多个属性类型,可以去掉 `;`
let person: {
name: string
sayHi(): void
} = {
name: 'jack',
sayHi() {}
}
解释:1. 使用 `{}` 来描述对象结构
2. 属性采用`属性名: 类型`的形式
3. 方法采用`方法名(参数: 参数的类型): 返回值类型`的形式
对象类型------使用类型别名
- 注意:直接使用 `{}` 形式为对象添加类型,会降低代码的可读性(不好辨识类型和值)
- 推荐:使用类型别名为对象添加类型
// 创建类型别名
type Person = {
name: string
sayHi(): void
}
// 使用类型别名作为对象的类型:
let person: Person = {
name: 'jack',
sayHi() {}
}
对象类型-------带有方法的参数类型
如果方法有参数,就在方法名后面的小括号中指定参数类型
type Person = {
greet(name: string): void
}
let person: Person = {
greet(name) {
console.log(name)
}
}
对象类型-------箭头函数形式的参数类型
type Person = {
greet: (name: string) => void
}
let person: Person = {
greet(name) {
console.log(name)
}
}
对象类型-------对象可选属性
对象的属性或方法,也可以是可选的,此时就用到 可选属性
type Config = {
url: string
method?: string
}
function myAxios(config: Config) {
console.log(config)
}
对象类型--------接口
当一个对象类型被多次使用时,也可以使用接口 interface 来描述对象的类型,达到复用的目的
解释:* 使用 `interface` 关键字来声明接口
* 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称,推荐以 `I` 开头
* 声明接口后,直接使用接口名称作为变量的类型
* 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)
interface IPerson {
name: string
age: number
sayHi(): void
}
let person: IPerson = {
name: 'jack',
age: 19,
sayHi() {}
}
对象类型------interface vs type(区别)
- 相同点:都可以给对象指定类型
-
不同点: * 接口,只能为对象指定类型
* 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名 -
约定:能使用 type 就是用 type
interface IPerson {
name: string
age: number
sayHi(): void
}
// 为对象类型创建类型别名
type IPerson = {
name: string
age: number
sayHi(): void
}
// 为联合类型创建类型别名
type NumStr = number | string
对象类型-------接口继承
如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用
比如,这两个接口都有 x、y 两个属性,重复写两次,可以,但很繁琐
interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z: number }
使用接口继承,来简化:
1. 使用 extends(继承)关键字实现了接口 Point3D 继承 Point2D
2. 继承后,Point3D 就有了 Point2D 的所有属性和方法( Point3D 同时有 x、y、z 三个属性)
interface Point2D { x: number; y: number }
// 继承 Point2D
interface Point3D extends Point2D {
z: number
}
// 继承后 Point3D 的结构:{ x: number; y: number; z: number }
8.交叉类型
使用交叉类型模拟接口继承的功能
- 语法:`&`,交叉类型(intersection types)
- 作用:组合现有的对象类型
- eg:Point3D 组合了 Point2D 和 后面的对象,Point3D 就同时具有了 Point2D 和 后面对象中的所有属性
// 使用 type 自定义类型来模拟 Point2D 和 Point3D
type Point2D = {
x: number
y: number
}
// 使用 交叉类型 来实现接口继承的功能:
// 使用 交叉类型 后,Point3D => { x: number; y: number; z: number }
// 也就是同时具有了 Point2D 和 后面对象 的所有的属性了
type Point3D = Point2D & {
z: number
}
let o: Point3D = {
x: 1,
y: 2,
z: 3
}
9.元组类型
限定值的类型,限定值的长度
- 元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型
- 元组类型可以确切地标记出有多少个元素,以及每个元素的类型
// 该示例中,元素有两个元素,每个元素的类型都是 number
let position: [number, number] = [116.2317, 39.5427]
10.类型推论
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型
- 换句话说:由于类型推论的存在,这些地方,**类型注解可以省略不写**
- 发生类型推论的 2 种常见场景: 1. 声明变量并初始化时 2. 根据参数类型决定函数返回值时
// 变量 age 的类型被自动推断为:number
let age = 18
// 函数返回值的类型被自动推断为:number
// 注意:函数参数一定要添加类型
function add(num1: number, num2: number) {
return num1 + num2
}
11.字面量类型
字面量类型:通过 const 定义,有具体的值,这个值可以作为类型
// 字面量类型:通过 const 定义,有具体的值,这个值可以作为类型
let str1="hello ts"
const str2="hello ts"
str1的类型----string str2的类型-------“hello ts”
字面量使用场景
明确的可选值的列表
type Sex='boy' | 'girl'
const sex:Sex='boy'
sex的值,只能是'box' 或 ‘girl’
12.枚举类型
// 枚举类型:使用 enum 定义一组命名常量,它描述一个值,该值可以是这些命名常量中的一个(一组可选值的列表)
// 数字枚举
enum Direct{
Up=10,Down=20,Left,Right
}
// 字符串枚举
enum Direct2{
Up="up",Down=20,Left,Right
}
let left:Direct=Direct.Left
let down:Direct=1 //错
export {}
枚举拿到的结果是 下标(索引)
枚举默认值:从零递增 ,若 up=10,则后面依次递增