TypeScript-基础
TypeScript 介绍
TypeScript(简称:TS)是 JavaScript 的超集(JS 有的 TS 都有)。
TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持)。
1 | // TypeScript 有明确的类型 |
TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行。
TS 属于静态类型的编程语言,即先编译检查再执行;JS 属于动态类型,即执行时检查。
TypeScript 相比 JS 的优势:
- 更早(写代码的同时)发现错误,减少找 Bug、改 Bug 时间,提升开发效率。
- 程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验。
- 强大的类型系统提升了代码的可维护性,使得重构代码更加容易。
- 支持最新的 ECMAScript 语法,优先体验最新的语法,让你走在前端技术的最前沿。
- TS 类型推断机制,不需要在代码中的每个地方都显示标注类型,让你在享受优势的同时,尽量降低了成本。
TypeScript 使用
安装编译 TS 的工具包:
因为浏览器和 Node.js 不能识别 TS 代码,所以通过工具包编译 TS 为 JS 代码
1 | npm i -g typescript |
验证是否安装成功:tsc -v
(查看 TypeScript 版本)
编译运行 TS 代码:
- 编写
.ts
文件 - 将 TS 代码编译为 JS 代码
- 执行 JS 代码
1 | tsc hello.ts |
简化运行 TS 的步骤:
安装 ts-node 包,直接在 Node.js 中执行 TS 代码
1 | npm i -g ts-node |
TypeScript 常用类型
类型注解
1 | let age1: number = 18 |
说明:代码中的 : number 就是类型注解。
作用:为变量添加类型约束。比如,上述代码中,约定变量 age 的类型为 number(数值类型)。
解释:约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错。
常用基础类型概述
- JS 已有类型
- 原始类型:number/string/boolean/null/undefined/symbol
- 对象类型:object(包括,数组、对象、函数等对象)。
- TS 新增类型
- 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等。
原始类型
原始类型:number/string/boolean/null/undefined/symbol
1 | let age: number = 18 |
与 JavaScript 代码中的类型一致
数组类型
数组类型的两种写法: (推荐使用 number[]
写法)
1 | let number: number[] = [1, 3, 5] |
当数组中有其他类型时,可以使用联合类型
1 | let arr: (number | string)[] = [1, 'a', 2, 'b'] |
类型别名
类型别名(自定义类型):为任意类型起别名。
使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用。
1 | type CustomArray = (number | string)[] |
- 使用 type 关键字来创建类型别名。
- 类型别名,可以是任意合法的变量名称。
- 创建类型别名后,直接使用该类型别名作为变量的类型注解即可。
函数类型
函数的类型实际上指的是:函数参数和返回值的类型。
为函数指定类型的两种方式:
- 单独指定参数、返回值的类型
- 同时指定参数、返回值的类型。
1 | // 单独指定参数、返回值的类型: |
解释:当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型。
注意:同时指定的形式只适用于函数表达式。
当没有返回值时,函数返回类型为:void
1 | function say(name: string): void { |
可选参数:
使用函数实现某个功能时,参数可以传也可以不传。这种情况下,在给函数参数指定类型时,就用到可选参数了。
1 | function say(name: string, count?: number): void { |
可选参数:在可传可不传的参数名称后面添加 ?(问号)。
注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数。
对象类型
- 直接使用
{}
来描述对象结构。属性采用属性名: 类型
的形式;方法采用方法名(): 返回值类型
的形式。 - 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如:
greet(name: string): void
)。 - 在一行代码中指定对象的多个属性类型时,使用
;
来分隔。
- 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉
;
。 - 方法的类型也可以使用箭头函数形式(比如:
{ sayHi: () => void }
)。
1 | let person: {name: string; age: number; sayHi(): void; sex?: boolean} = { |
对象属性或方法也可以使用可选属性,用?
来表示
接口
当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。
- 使用 interface 关键字来声明接口。
- 接口名称,可以是任意合法的变量名称。
- 声明接口后,直接使用接口名称作为变量的类型。
- 因为每一行只有一个属性类型,因此,属性类型后没有
;
。
1 | interface Person { |
interface 和 type 的对比:
- 相同点:都可以给对象指定类型。
- 不同点:
- 接口,只能为对象指定类型。
- 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名。
继承:如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用。
- 使用 extends(继承)关键字实现了接口 Point3D 继承 Point2D。
- 继承后,Point3D 就有了 Point2D 的所有属性和方法(此时,Point3D 同时有 x、y、z 三个属性)。
1 | interface Point2D { x: number; y: number } |
元组
元组类型是另一种类型的数组,能够指定包含元素个数,以及特定索引对应的类型
1 | // 普通数组写法 |
类型推理
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型。
常见场景:
- 声明变量并初始化时
- 决定函数返回值时。
注意:这两种情况下,类型注解可以省略不写!
类型断言
当需要更明确一个值的类型,可以使用类型断言来指定更具体的类型
1 | // 被识别为 const aLink: HTMLElement,没办法使用a标签的href等属性 |
- 使用 as 关键字实现类型断言。
- 关键字 as 后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型)。
- 通过类型断言,aLink 的类型变得更加具体,这样就可以访问 a 标签特有的属性或方法了。
字面量类型
1 | let str1 = 'Hello TS' |
通过 TS 类型推理机制:
- str1 的类型为: string,因为是一个变量,它的值可以是任意字符串
- str2 的类型为: ‘Hello TS’,因为是一个常亮,其值只能是 ‘Hello TS’,这就是字面量类型
除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用。
使用模式:字面量类型配合联合类型一起使用。
使用场景:用来表示一组明确的可选值列表。例如游戏当中的方向键只有上下左右。
1 | function change(direction: 'up' | 'down' | 'left' | 'right') { |
参数 direction 的值只能是 up/down/left/right 中的任意一个。
优势:相比于 string 类型,使用字面量类型更加精确、严谨。
枚举
枚举可以理解为字面量类型+联合类型组合,可以表示一组明确的可选值
枚举:定义一组命名常量。描述一个值,该值可以是这些命名常量中的一个
1 | enum Direction { Up, Down, Left, Right } |
- 使用 enum 关键字定义枚举。
- 约定枚举名称、枚举中的值以大写字母开头。
- 枚举中的多个值之间通过
,
分隔。 - 定义好枚举后,直接使用枚举名称作为类型注解。
- 访问枚举成员,可以通过
.
语法访问
枚举成员是有值的,默认从0开始递增。
数字枚举:枚举成员的值是数字的枚举,可以自定义枚举成员值
1 | // Down -> 11, Left -> 12, Right -> 13 |
字符串枚举:枚举成员的值是字符串的枚举
1 | enum Direction { |
注意:字符串枚举没有自增长行为,所以每个字符串枚举的成员必须有初始值
因为枚举不值用于类型,同时还提供值,所以在编译阶段会被编译成 JS 代码
any 类型
any 类型可以是该值进行任何类型操作,并且不会有代码其实
1 | let obj: any = { x: 0 } |
注意:!!不推荐使用 any 类型!!,因为这样会让 TS 失去意义,可能造成不必要的错误
隐式的 any 类型情况:
- 声明变量不提供类型也不提供默认值;
- 函数参数不加类型
typeof
typeof 操作符能像 JS 一样,获取数据的类型
同时当出现在类型注解的位置时,可以在类型上下文中引用变量或属性的类型
1 | let p = { x: 1, y: 2} |
注意:typeof 只能查询变量或属性的类型,无法查询其他形式的类型