1. 类型注解

目标:能够理解什么是ts的类型注解

示例代码:

  1. let age: number = 18
  1. 说明:代码中的 : number 就是类型注解
  2. 作用:为变量添加类型约束。比如,上述代码中,约定、约束变量 age 的类型为 number 类型
  3. 解释:约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错

错误演示:

  1. // 错误演示:
  2. // 不能将类型 "string" 分配给类型 "number"
  3. // age = '18'
  4. // 错误原因:将 string 类型的值赋值给了 number 类型的变量,类型不一致
  5. let age: number = '18'

2. 原始类型

目标:能够理解 ts 中原始类型的使用

知识点:

TS 中的常用基础类型细分为两类:① JS 已有类型 ② TS 新增类型

  1. JS 已有类型
  • 原始类型:number / string / boolean / null / undefined/ symbol
  • 对象类型:object (包括,数组、对象、函数等对象)
  1. TS 新增类型
  • 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等
  • 注意:
    • 原始类型 在 TS 和 JS 中写法一致
    • 对象类型 在 TS 中更加细化,每个具体的对象(比如,数组、对象、函数)都有自己的类型语法

**首先,我们先来看原始类型:

  • 原始类型:number / string / boolean / null / undefined/ symbol
  • 特点:简单,这些类型,完全按照 JS 中类型的名称来书写 ```typescript let age: number = 10 let name: string = ‘黑马程序员’ let bol: boolean = true let undefinedVal: undefined = undefined let nullVal: null = null

// —— 以下代码在浏览器运行 ——

// Symbol 产生的原因 // ES5 中的对象属性名都是字符串,很容器造成属性名的冲突, // 为了从根本上解决属性名冲突的问题,ES6 中引入了 Symbol

// Symbol 是一种原始数据类型,表示独一无二的值

let obj = { name: ‘tom’ } obj.name = ‘jerry’

// 为 obj 对象添加属性,并且还要保证属性名一定不会重复 let gender = Symbol() obj[gender] = ‘男’

// 取值: console.log(obj[gender])

  1. <a name="ndfHP"></a>
  2. ## 3. 数组类型
  3. > 目标:掌握 ts 中数组类型的两种写法
  4. **知识点:**
  5. TypeScript 像 JavaScript 一样可以操作数组元素。 有两种方式可以定义数组
  6. 第一种,可以在元素类型后面接上 **[],表示由此类型元素组成的一个数组**:
  7. ```typescript
  8. let list: number[] = [1, 2, 3]

第二种方式是使用数组泛型:Array<元素类型>

  1. let list: Array<number> = [1, 2, 3]

推荐:使用第一种方式,写法更简洁

4. 联合类型

目标:能够通过联合类型将多个类型组合成一个类型

知识点:

需求:数组中既有 number 类型,又有 string 类型,这个数组的类型应该如何写 ?

  1. // 此处 () 的目的是为了将提升优先级,表示数组由 number 类型 以及 string 类型组成
  2. let arr: (number | string)[] = [1, 'Tom', 3, 'Jerry']
  3. // 错误演示
  4. // 不能将类型 "boolean" 分配给类型 "string | number"
  5. // let arr: (number | string)[] = [10, 'Tom', true]

解释:
| (竖线) 在 TS 中叫做联合类型,即:由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种

注意:
这是 TS 中联合类型的语法,只有一根竖线,不要与 JS 中的或(|| 或)混淆了

  1. // 思考:该类型的含义?
  2. let arr: number | string[]
  3. // arr = [1 , 2, 3] // 会报错
  4. // arr = ['a', 'b', 'c'] // 代码正常解析
  5. arr = 1
  6. // 答案:要么是 number 类型,或者是 string[] 类型的数组

5. 类型别名

目标:能够使用类型别名给类型起别名

知识点:

我们可以使用变量 (let、const、var) 为值声明别名,类似的,还可以为类型声明别名,具体做法如下:

  1. 类型别名(自定义类型):为任意类型起别名
  2. 使用场景:当同一类型 (复杂) 被多次使用时,可以通过类型别名,简化该类型的使用 ```typescript type CustomArray = (number | string)[]

let arr1: CustomArray = [1, ‘a’, 3, ‘b’] let arr2: CustomArray = [‘x’, ‘y’, 6, 7]

  1. 解释:
  2. 1. 使用 `type` 关键字来创建自定义类型
  3. 1. 类型别名(比如,此处的 CustomArray)可以是任意合法的变量名称
  4. 1. 推荐使用大写字母开头
  5. 1. 创建类型别名后,直接使用该类型别名作为变量的类型注解即可
  6. <a name="xyxGk"></a>
  7. ## 6. 函数类型
  8. <a name="WpZIU"></a>
  9. ### 6.1 函数类型-参数和返回值
  10. > 目标:能够给函数指定类型
  11. **知识点:**
  12. 1. 函数的类型实际上指的是:函数参数 返回值的类型
  13. 1. 为函数指定类型的两种方式:
  14. - 单独指定参数、返回值的类型
  15. - 同时指定参数、返回值的类型
  16. **方式一:**单独指定参数、返回值的类型
  17. ```typescript
  18. // 函数声明
  19. function add(num1: number, num2: number): number {
  20. return num1 + num2
  21. }
  22. // 箭头函数
  23. const add = (num1: number, num2: number): number => {
  24. return num1 + num2
  25. }

方式二:同时指定参数、返回值的类型

  1. 解释:当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型
  2. 注意:这种形式只适用于函数表达式 ```typescript // 创建函数自定义类型 type AddFn = (num1: number, num2: number) => number

// 使用自定义类型作为函数 add 的类型 const add: AddFn = (num1, num2) => { return num1 + num2 }

  1. <a name="Ppf78"></a>
  2. ### 6.2 函数类型-void 类型
  3. > 目标:能够了解 void 类型的使用
  4. **知识点:**
  5. 如果函数没有返回值,那么,函数返回值类型为:void
  6. ```typescript
  7. function greet(name: string): void {
  8. console.log('Hello', name)
  9. }

注意:

  1. 如果一个函数没有返回值,此时,在 TS 的类型中,应该使用 void 类型
  2. 注意:不要与 undefined 类型混淆 ```typescript // 如果什么都不写,此时,add 函数的返回值类型为: void const add = () => {}

// 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同 const add = (): void => {}

// 但如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以 const add = (): undefined => { // 此处,返回的 undefined 是 JS 中的一个值 return undefined }

  1. <a name="IwSTp"></a>
  2. ### 6.3 函数类型-可选参数
  3. > 目标:能够给函数设置可选参数类型
  4. **知识点:**
  5. 1. 使用函数实现某个功能时,参数可传也可以不传。这种情况下,给函数参数指定类型时,就用到可选参数了
  6. 1. 可选参数:在可传可不传的参数名称后面添加 ?(问号)
  7. 1. 比如,数组的 slice 方法,可以 slice() 也可以 slice(1) 还可以 slice(1, 3)
  8. ```typescript
  9. function mySlice(start?: number, end?: number): void {
  10. console.log('起始索引:', start, '结束索引:', end)
  11. }

注意:

  1. 可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数
  2. 注意:参数默认值和可选参数互斥的,一般只需要指定一种即可
  • 注意:如果参数有默认值,那么该参数默认就是可选的 ```typescript // 正确用法 function handle1(start: number, end?: number): void { console.log(‘起始索引:’, start, ‘结束索引:’, end) }

// 错误用法演示 function handle2(start?: number, end: number): void { console.log(‘起始索引:’, start, ‘结束索引:’, end) }

// 错误用法演示 // 参数默认值和可选参数互斥的,要么是默认值,要么是可选参数 // 如果一个参数有默认值,那么该参数默认就是有值的,所以,就没必须要在通过 ? 来指定可选了 function handle3(start?: number, end: number = 1): void { console.log(‘起始索引:’, start, ‘结束索引:’, end) }

  1. <a name="vphLH"></a>
  2. ## 7. 对象类型
  3. <a name="VjXT7"></a>
  4. ### 7.1 对象类型-基本使用
  5. > 目标:掌握对象类型的基本使用
  6. **知识点:**
  7. 1. JS 中的对象是由属性和方法构成的,而 TS 对象的类型就是在描述对象的结构(有什么类型的属性和方法)
  8. 1. 对象类型的写法:
  9. ```typescript
  10. // 空对象
  11. let person: {} = {}
  12. // 有属性的对象
  13. let person: { name: string } = {
  14. name: '黑马程序员'
  15. }
  16. // 既有属性又有方法的对象
  17. // 在一行代码中指定对象的多个属性类型时,使用 `;`(分号)来分隔
  18. let person: { name: string; sayHi(name: string): void } = {
  19. name: 'jack',
  20. sayHi(name) {}
  21. }
  22. // 对象中如果有多个类型,可以换行写
  23. // 通过换行来分隔多个属性类型,可以去掉 `;`
  24. let person: {
  25. name: string
  26. sayHi(name: string): void
  27. } = {
  28. name: 'jack',
  29. sayHi(name) {}
  30. }

解释:

  1. 使用 {} 来描述对象结构
  2. 属性采用 属性名: 类型 的形式
  3. 方法采用 方法名(参数: 参数的类型): 返回值类型 的形式

7.2 对象类型-使用类型别名

目标:能够使用类型别名定义对象类型

  1. 注意:直接使用 {} 形式为对象添加类型,会降低代码的可读性(不好辨识类型和值)
  2. 推荐:使用 类型别名 为对象添加类型 ```typescript // 创建类型别名 type Person = { name: string sayHi(): void // sayHi: () => void }

// 使用类型别名作为对象的类型: let person: Person = { name: ‘jack’, sayHi() {} }

  1. <a name="oVcpt"></a>
  2. ### 7.3 对象类型-带有参数的方法类型
  3. 1. 如果方法有参数,就在方法名后面的小括号中指定参数类型
  4. ```typescript
  5. type Person = {
  6. greet(name: string): void
  7. }
  8. let person: Person = {
  9. greet(name) {
  10. console.log(name)
  11. }
  12. }

7.4 对象类型-箭头函数形式的方法类型

  1. 方法的类型也可以使用箭头函数形式 ```typescript type Person = { greet: (name: string) => void }

let person: Person = { greet(name) { console.log(name) } }

  1. <a name="Ok1fz"></a>
  2. ### 7.5 对象类型-对象可选属性
  3. 1. 对象的属性或方法,也可以是可选的,此时就用到 可选属性 了
  4. 2. 比如,我们在使用 axios({ ... }) 时,如果发送 GET 请求,method 属性就可以省略
  5. 2. 可选属性的语法与函数可选参数的语法一致,都使用 ? 来表示
  6. ```typescript
  7. type Config = {
  8. url: string
  9. method?: string
  10. }
  11. function myAxios(config: Config) {
  12. console.log(config)
  13. }

7.6 对象类型-接口

目标:能够使用接口类型来为对象指定类型

知识点:

当一个对象类型被多次使用时,也可以使用接口 (interface) 来描述对象的类型,达到复用的目的

解释:

  1. 使用 interface 关键字来声明接口
  2. 接口名称 (比如,此处的 IPerson),可以是任意合法的变量名称,推荐以 I 开头
  3. 声明接口后,直接使用接口名称作为变量的类型
  4. 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号) ```typescript interface IPerson { name: string age: number sayHi(): void }

let person: IPerson = { name: ‘jack’, age: 19, sayHi() {} }

  1. <a name="XSp6N"></a>
  2. ### 7.7 对象类型-interface vs type
  3. > 目标:能够理解interface和type的相同点和不同点
  4. 1. interface(接口)和 type(类型别名)的对比:
  5. - 相同点:都可以给对象指定类型
  6. - 不同点:
  7. - 接口,只能为对象指定类型
  8. - 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名
  9. 2. 注意:interface 和 type 在使用上还有其他的不同之处,请 [参考文档](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces) 说明
  10. 2. 约定:能使用 type 就是用 type
  11. ```typescript
  12. interface IPerson {
  13. name: string
  14. age: number
  15. sayHi(): void
  16. }
  17. // 为对象类型创建类型别名
  18. type IPerson = {
  19. name: string
  20. age: number
  21. sayHi(): void
  22. }
  23. // 为联合类型创建类型别名
  24. type NumStr = number | string

7.8 对象类型-接口继承

目标:能够通过接口继承实现复用

知识点:

如果两个接口之间有相同的属性或方法,可以 将公共的属性或方法抽离出来,通过继承来实现复用
比如,这两个接口都有 x、y 两个属性,重复写两次,可以,但很繁琐

  1. interface Point2D { x: number; y: number }
  2. interface Point3D { x: number; y: number; z: number }

使用 接口继承 来简化:

  1. 使用 extends(继承) 关键字实现了接口 Point3D 继承 Point2D
  2. 继承后,Point3D 就有了 Point2D 的所有属性和方法(此时,Point3D 同时有 x、y、z 三个属性) ```typescript interface Point2D { x: number; y: number }

// 继承 Point2D interface Point3D extends Point2D { z: number }

// 继承后 Point3D 的结构:{ x: number; y: number; z: number }

  1. <a name="IsV2h"></a>
  2. ## 8. 交叉类型
  3. > 目标:能够使用交叉类型模拟接口继承的功能
  4. **知识点:**
  5. 使用类型别名的方式,无法使用 extend 继承,如果想实现简化的操作,可以使用交叉类型来实现继承的功能
  6. 1. 语法:**&** 交叉类型(intersection types)
  7. 1. 作用:组合现有的对象类型
  8. 1. 比如:Point3D 包含 Point2D 和 后面的对象,所以 Point3D 就同时具有了 Point2D 和 后面对象中的所有属性
  9. ```typescript
  10. // 使用 type 自定义类型来模拟 Point2D 和 Point3D
  11. type Point2D = {
  12. x: number
  13. y: number
  14. }
  15. // 使用 交叉类型 来实现接口继承的功能:
  16. // 使用 交叉类型 后,Point3D => { x: number; y: number; z: number }
  17. // 也就是同时具有了 Point2D 和 后面对象 的所有的属性了
  18. type Point3D = Point2D & {
  19. z: number
  20. }
  21. let o: Point3D = {
  22. x: 1,
  23. y: 2,
  24. z: 3
  25. }

9. 元组类型

目标:能够理解什么是元组

场景:

在地图中,使用经纬度坐标来标记位置信息,可以使用数组来记录坐标,那么该数组中只有两个元素,并且这两个元素都是数值类型

使用 number[] 的缺点:不严谨,因为该类型的数组中可以出现任意多个数字

  1. let position: number[] = [116.2317, 39.5427]

知识点:

更好的方式:元组 Tuple

  1. 元组类型是另一种类型的数组,它 确切地知道包含多少个元素,以及特定索引对应的类型
  2. 元组类型可以确切地标记出有多少个元素,以及每个元素的类型
    1. // 该示例中,元素有两个元素,每个元素的类型都是 number
    2. let position: [number, number] = [116.2317, 39.5427]
    实际上,React 中 useState hook 的返回值类型就是一个元组类型
    1. // 因为对于 useState 来说,它的返回值长度固定切每个索引对应的元素类型也是知道的
    2. const [loading, setLoading] = useState(false)

10. 类型推论

目标:能够知道什么是TS的类型推论

知识点:

  1. 在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型
  2. 换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写
  3. 发生类型推论的 2 种常见场景:
  • 声明变量并初始化时
  • 决定函数返回值时 ```typescript // 变量 age 的类型被自动推断为:number let age = 18

// 函数返回值的类型被自动推断为:number // 注意:函数参数一定要添加类型 function add(num1: number, num2: number) { return num1 + num2 }

  1. **推荐:**
  2. 1. 能省略类型注解的地方就省略,充分利用TS类型推论的能力,提升开发效率
  3. 1. 技巧:如果不知道类型,可以通过鼠标放在变量名称上,利用 VSCode 的提示来查看类型
  4. 1. 推荐:在 VSCode 中写代码的时候,多看方法、属性的类型,养成写代码看类型的习惯(充分发挥 VSCode 的能力)
  5. <a name="vLvQU"></a>
  6. ## 11. 字面量类型
  7. <a name="KeXzl"></a>
  8. ### 11.1 字面量类型说明
  9. > 目标:能够知道 TS 的字面量类型是什么
  10. **知识点:**
  11. 思考以下代码,两个变量的类型分别是什么?
  12. ```typescript
  13. let str1 = 'Hello TS'
  14. const str2 = 'Hello TS'

通过 TS 类型推论机制(技巧),可以得到答案:

  1. 变量 str1 的类型为:string
  2. 变量 str2 的类型为:’Hello TS’

注意:此处的 ‘Hello TS’,就是一个 字面量类型,也就是说某个特定的字符串也可以作为 TS 中的类型
实际上,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用

  1. // 字面量类型:{ name: 'jack' }
  2. const obj: { name: 'jack' } = { name: 'jack' }
  3. // 字面量类型:[]
  4. const arr: [] = []
  5. // 字面量类型:18
  6. const age: 18 = 18
  7. // 字面量类型:false
  8. const falseValue: false = false

11.2 使用模式和场景

目标:能够用字面量类型配合联合类型一起使用

知识点:

  1. 使用模式:字面量类型配合联合类型一起使用
  2. 使用场景:用来表示一组明确的可选值列表
  3. 比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个 ```typescript // 使用自定义类型: type Direction = ‘up’ | ‘down’ | ‘left’ | ‘right’

function changeDirection(direction: Direction) { console.log(direction) }

// 调用函数时,会有类型提示: changeDirection(‘up’)

  1. 解释:参数 direction 的值只能是 up / down / left / right 中的任意一个<br />优势:相比于 string 类型,使用字面量类型更加精确、严谨
  2. <a name="ejqko"></a>
  3. ## 12. 枚举类型
  4. <a name="eoTcN"></a>
  5. ### 12.1 枚举类型-基本使用
  6. > 目标:能够了解 TS 中的枚举类型
  7. 知识点:
  8. 1. 枚举的功能类似于 字面量类型+联合类型 组合的功能,也可以表示一组明确的可选值
  9. 1. 枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个
  10. ```typescript
  11. // 创建枚举类型
  12. enum Direction { Up, Down, Left, Right }
  13. // 使用枚举类型
  14. function changeDirection(direction: Direction) {
  15. console.log(direction)
  16. }
  17. // 调用函数时,需要应该传入:枚举 Direction 成员的任意一个
  18. // 类似于 JS 中的对象,直接通过 点(.)语法 访问枚举的成员
  19. changeDirection(Direction.Up)

解释:

  1. 使用 enum 关键字定义枚举
  2. 约定枚举名称以 大写字母开头
  3. 枚举中的多个值之间通过 ,(逗号)分隔
  4. 定义好枚举后,直接使用枚举名称作为类型注解

12.2 枚举类型-数字枚举

目标:能够了解什么是数字枚举

知识点:

  1. 问题:我们把枚举成员作为了函数的实参,它的值是什么呢 ?
  2. 解释:通过将鼠标移入 Direction.Up,可以看到枚举成员 Up 的值为 0,

image.png

  1. 注意:枚举成员是有值的,默认为:从 0 开始自增的数值
  2. 我们把枚举成员的值为数字的枚举,称为:数字枚举
  3. 当然,也可以给枚举中的成员初始化值 ```typescript // Down -> 11、Left -> 12、Right -> 13 // enum Direction { Up = 10, Down, Left, Right }

enum Direction { Up = 2, Down = 4, Left = 8, Right = 16 }

  1. <a name="f8SxS"></a>
  2. ### 12.3 枚举类型-字符串枚举
  3. > 目标:能够了解什么是字符串枚举
  4. **知识点:**
  5. 1. 字符串枚举:枚举成员的值是字符串
  6. 1. 注意:字符串枚举没有自增长行为,因此:字符串枚举的每个成员必须有初始值
  7. ```typescript
  8. enum Direction {
  9. Up = 'UP',
  10. Down = 'DOWN',
  11. Left = 'LEFT',
  12. Right = 'RIGHT'
  13. }

12.4 枚举类型-枚举实现原理

目标:能够了解枚举类型的实现原理

知识点:

  1. 枚举是 TS 为数不多的非 JavaScript 类型级扩展(不仅仅是类型)的特性之一
  2. 因为:其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值(枚举成员都是有值的)
  3. 也就是说,其他的类型会在编译为 JS 代码时自动移除。但是,枚举类型会被编译为 JS 代码 ```typescript enum Direction { Up = ‘UP’, Down = ‘DOWN’, Left = ‘LEFT’, Right = ‘RIGHT’ }

// 会被编译为以下 JS 代码: // 整体来看:将枚举转化成了 JS 中的一个对象 / var Direction = { Up: ‘UP’, Down: ‘DOWN’, Left: ‘LEFT’, Right: ‘RIGHT’ } /

var Direction; (function (Direction) { Direction[“Up”] = “UP”; Direction[“Down”] = “DOWN”; Direction[“Left”] = “LEFT”; Direction[“Right”] = “RIGHT”; })(Direction || (Direction = {}));

  1. - 说明:枚举与前面讲到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表
  2. - 一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效
  3. <a name="UpRDt"></a>
  4. ## 13. any 类型
  5. > 目标:能够知道 TS 中的 any 类型
  6. 知识点:
  7. 1. 原则:不推荐使用 any!这会让 TypeScript 变为 AnyScript”(失去 TS 类型保护的优势)
  8. 1. 解释:因为当值的类型为 any 时,可以对该值进行任意操作,并且不会有代码提示
  9. ```typescript
  10. let obj: any = { x: 0 }
  11. obj.bar = 100
  12. obj()
  13. const n: number = obj

尽可能的避免使用 any 类型,除非临时使用 any 来“避免”书写很长、很复杂的类型
其他隐式具有 any 类型的情况

  1. 声明变量不提供类型也不提供默认值
  2. 函数参数不加类型

注意:因为不推荐使用 any,所以,这两种情况下都应该提供类型


14. 类型断言

目标:能够使用 TS 中的类型断言指定更加具体的类型

场景:

有时候你会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。 比如:

  1. // 假设页面中有个 id 为 link 的 a 标签:
  2. // <a id="link" href="http://itcast.cn/">传智播客</a>
  3. // 我们希望通过 DOM 拿到 a 标签的 href 属性
  4. const aLink = document.getElementById('link')

该方法返回值的类型是 HTMLElement,该类型只包含所有标签公共的属性或方法,不包含 a 标签特有的 href 等属性,因此,这个类型太宽泛(不具体),无法操作 href 等 a 标签特有的属性或方法

解决方式:这种情况下就需要使用类型断言指定更加具体的类型

知识点:

使用类型断言:

  1. 使用 as 关键字 实现类型断言
  2. 关键字 as 后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型)
  3. 通过类型断言,aLink 的类型变得更加具体,这样就可以访问 a 标签特有的属性或方法了
    1. // 使用类型断言来指定为更加具体的 HTMLAnchorElement 类型
    2. const aLink = document.getElementById('link') as HTMLAnchorElement

另一种语法,使用 <> 语法,这种语法形式不常用,了解即可:

  1. // 该语法,知道即可:
  2. const aLink = <HTMLAnchorElement>document.getElementById('link')

技巧:在浏览器控制台,通过 proto 可以获取 DOM 元素的类型


15. typeof 运算符

目标:能够知道 TS 中的 typeof 运算符的作用

知识点:

众所周知,JS 中提供了 typeof 操作符,用来在 JS 中获取数据的类型

  1. console.log(typeof 'Hello world') // ? string

TS 也提供了 typeof 操作符

  1. 可以在 类型上下文 中引用变量或属性的类型(类型查询)
  2. 使用场景:根据已有变量的值,获取该值的类型,来简化类型书写 ```typescript // let p = { x: 1, y: 2 } // function formatPoint(point: { x: number; y: number }) {} // formatPoint(p)

// 此处使用 typeof p 获取变量 p 在 TS 中的类型: function formatPoint(point: typeof p) {} formatPoint(p) ```

解释:

  1. 使用 typeof 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同
  2. typeof 出现在类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于 JS 代码)
  3. 注意:typeof 只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)