TypeScript极速梳理
0. 前言
我们在学习 Vue 的时候会发现,现在很多的 Vue 开发都是采用 Vue
+ TypeScript
的方式,对于没接触过 TypeScript 的小伙伴来说脑瓜子肯定懵懵的😵💫,可能就要问了:啥是 TypeScript 啊?哥们儿都会 JavaScript 了🤔,为什么还要使用 TypeScript 啊?
下面就来回答一下上面这两个问题吧:
什么是 TypeScript ?
TypeScript 是一种由微软开发的自由和开源的编程语言,它是 JavaScript 的一个超集,并添加了静态类型、类、接口和泛型等特性。这意味着你可以在 TypeScript 中编写代码,然后将其编译为纯 JavaScript 代码,以便在任何支持 JavaScript 的环境中运行。
为什么使用 TypeScript ?
对于搭配 TypeScript 使用 Vue,Vue 官方这样介绍:
像 TypeScript 这样的类型系统可以在编译时通过静态分析检测出很多常见错误。这减少了生产环境中的运行时错误,也让我们在重构大型项目的时候更有信心。通过 IDE 中基于类型的自动补全,TypeScript 还改善了开发体验和效率。
Vue 本身就是用 TypeScript 编写的,并对 TypeScript 提供了一等公民的支持。所有的 Vue 官方库都自带了类型声明文件,开箱即用。
1. 类型声明
1 | let a: string //变量a只能存储字符串 |
2. 类型推断
1 | let d = -99 //TypeScript会推断出变量d的类型是数字 |
3. 类型总览
JavaScript
中的数据类型
string
、number
、boolean
、null
、undefined
、bigint
、symbol
、object
PS:其中 object
包含: Array
、Function
、Date
、…
TypeScript
中的数据类型:
- 以上 JS 所有
- 四个新类型:
void
、never
、unknown
、any
、enum
、tuple
- 自定义类型:
type
、interface
PS: JS 中的这三个构造函数: Number
、String
、Boolean
,他们只用于包装对象,正常开发时,很少去使用他们,在 TS 中也是同理。
1 | let n = 56 |
类型总览
类型 | 描述 | 举例 |
---|---|---|
number | 任意数字 | 1,-33,2.5 |
string | 任意字符串 | ‘hello’,’ok’,’你好’ |
boolean | 布尔值 true 或 false |
true、false |
字⾯量 | 值只能是字⾯量值 | 值本身 |
any | 任意类型 | 1、’hello’、true … |
unknown | 类型安全的 any |
1、’hello’ 、true … |
never | 不能是任何值 | 无值 |
void | 空 或 undefined |
空 或 undefined |
object | 任意的 JS 对象 |
{name:’张三’} |
tuple | 元素, TS 新增类型,固定⻓度数组 |
[4,5] |
enum | 枚举, TS 中新增类型 |
enum{A, B} |
4. 常用类型
4.1 字面量
1 | let a: '你好' //a的值只能为字符串“你好” |
4.2 any
any
的含义是:任意类型,一旦将变量类型限制为 any
,那就意味着放弃了对该变量的类型检查。
1 | //明确的表示a的类型是any —— 显式的any |
PS: any
类型的变量,可以赋值给任意类型的变量。
1 | /* 注意点:any类型的变量,可以赋值给任意类型的变量 */ |
4.3 unknown
unknown
的含义是:未知类型。
注意:
unknown
可以理解为一个类型安全的any
。unknown
适用于:开始不知道数据的具体类型,后期才能确定数据的类型。
1 | // 设置a的类型为unknown |
若就是想把 a
赋值给 x
,可以用以下三种写法:
1 | // 设置a的类型为unknown |
any
后 .
任何的东西都不会报错,而 unknown
正好与之相反。
1 | let str1: string = 'hello' |
4.4 never
never
的含义是:任何值都不是,简言之就是不能有值, undefined
、 null
、 ''
、 0
都不行!
几乎不用
never
去直接限制变量,因为没有意义,例如:1
2
3
4
5
6
7/* 指定a的类型为never,那就意味着a以后不能存任何的数据了 */
let a: never
// 以下对a的所有赋值都会有警告
a = 1
a = true
a = undefined
a = nullnever
一般是 TypeScript 主动推断出来的,例如:1
2
3
4
5
6
7
8
9// 指定a的类型为string
let a: string
// 给a设置一个值
a = 'hello'
if (typeof a === 'string') {
a.toUpperCase()
} else {
console.log(a) // TypeScript会推断出此处的a是never,因为没有任何一个值符合此处的逻辑
}never
也可用于限制函数的返回值。1
2
3
4// 限制demo函数不需要有任何返回值,任何值都不行,像undeifned、null都不行
function demo(): never {
throw new Error('程序异常退出')
}
4.5 void
void
的含义是: 空
或 undefined
,严格模式下不能将 null
赋值给 void
类型。
1 | let a: void = undefined |
void
常用于限制函数返回值:
1 | // 无警告 |
4.6 object
关于 Object
与 object
,直接说结论:在类型限制时, Object
几乎不用,因为范围太大了,无意义。
object
的含义:任何【非原始值类型】,包括:对象、函数、数组等,限制的范围比较宽泛,用得少。1
2
3
4
5
6
7
8
9
10
11
12
13
14let a: object //a的值可以是任何【非原始值类型】,包括:对象、函数、数组等
// 以下代码,是将【非原始类型】赋给a,所以均无警告
a = {}
a = { name: '张三' }
a = [1, 3, 5, 7, 9]
a = function () { }
// 以下代码,是将【原始类型】赋给a,有警告
a = null // 警告:不能将类型“null”分配给类型“object”
a = undefined // 警告:不能将类型“undefined”分配给类型“object”
a = 1 // 警告:不能将类型“number”分配给类型“object”
a = true // 警告:不能将类型“boolean”分配给类型“object”
a = '你好' // 警告:不能将类型“string”分配给类型“object”Object
的含义:Object
的实例对象,限制的范围太大了,几乎不用。1
2
3
4
5
6
7
8
9
10
11
12
13
14let a: Object //a的值必须是Object的实例对象
// 以下代码,均无警告,因为给a赋的值,都是Object的实例对象
a = {}
a = { name: '张三' }
a = [1, 3, 5, 7, 9]
a = function () { }
a = 1 // 1不是Object的实例对象,但其包装对象是Object的实例
a = true // true不是Object的实例对象,但其包装对象是Object的实例
a = '你好' // “你好”不是Object的实例对象,但其包装对象是Object的实例
// 以下代码均有警告
a = null // 警告:不能将类型“null”分配给类型“Object”
a = undefined // 警告:不能将类型“undefined”分配给类型“Object”实际开发中,限制一般对象,通常使用以下形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 限制person对象的具体内容,使用【,】分隔,【?】代表可选属性
let person: { name: string, age?: number }
// 限制car对象的具体内容,使用【;】分隔,必须有price和color属性,其他属性不去限制,有没有都行
let car: { price: number; color: string;[k: string]: any }
// 限制student对象的具体内容,使用【回车】分隔
let student: {
id: string
grade: number
}
// 以下代码均无警告
person = { name: '张三', age: 18 }
person = { name: '李四' }
car = { price: 100, color: '红色' }
student = { id: 'tetqw76te01', grade: 3 }限制函数的参数、返回值,使用以下形式:
1
2
3
4let demo: (a: number, b: number) => number
demo = function (x, y) {
return x + y
}限制数组,使用以下形式:
1
2
3
4let arr1: string[] // 该行代码等价于: let arr1: Array<string>
let arr2: number[] // 该行代码等价于: let arr2: Array<number>
arr1 = ['a', 'b', 'c']
arr2 = [1, 3, 5, 7, 9]
4.7 tuple
tuple
就是一个长度固定的数组。
1 | let t: [string, number] |
4.8 enum
enum
是枚举。
1 | // 定义一个枚举 |
5. 自定义类型
自定义类型,可以更灵活的限制类型。
1 | // 性别的枚举 |
6. 抽象类
常规类:
1 | class Person { |
继承:
1 | // Person类 |
抽象类:不能去实例化,但可以被别人继承,抽象类里有抽象方法。
1 | // Person(抽象类) |
7. 接口
接口用于限制一个类中包含哪些属性和方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// Person接口
interface Person {
// 属性声明
name: string
age: number
// 方法声明
speak(): void
}
// Teacher实现Person接口
class Teacher implements Person {
name: string
age: number
// 构造器
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 方法
speak() {
console.log('你好!我是老师:', this.name)
}
}接口是可以重复声明的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// Person接口
interface PersonInter {
// 属性声明
name: string
age: number
}
// Person接口
interface PersonInter {
// 方法声明
speak(): void
}
// Person类继承PersonInter
class Person implements PersonInter {
name: string
age: number
// 构造器
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 方法
speak() {
console.log('你好!我是老师:', this.name)
}
}【接口】与【自定义类型】的区别:
接口可以:
- 当自定义类型去使用。
- 可以限制类的结构。
自定义类型:
- 仅仅就是自定义类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// Perosn接口
interface Perosn {
// 应该具有的属性
name: string
age: number
// 应该具有的方法
speak(): void
}
//Person类型
/* type Perosn = {
// 应该具有的属性
name: string
age: number
// 应该具有的方法
speak(): void
} */
// 接口当成自定义类型去使用
let person: Perosn = {
name: '张三',
age: 18,
speak() {
console.log('你好!')
}
}【 接口 】与【 抽 象 类 】 的 区 别:
抽象类:
- 可以有普通方法,也可以有抽象方法。
- 使用
extends
关键字去继承抽象类 。
接口中:
- 只能有抽象方法。
- 使用
implements
关键字去实现接口。
抽象类举例:
1 | // 抽象类 —— Person |
接口举例:
1 | // 接口 —— Person,只能包含抽象方法 |
8. 属性修饰符
属性修饰符 | 属性权限 | 备注 |
---|---|---|
readonly | 只读属性 | 属性无法修改 |
public | 公开的 | 可以在类、子类和对象中修改 |
protected | 受保护的 | 可以在类、子类中修改 |
private | 私有的 | 可以在类中修改 |
9. 泛型
如果你想了解更多关于泛型的知识,此处可以类比Java泛型 这篇文章进行学习哦🎈
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确 定),此时就需要泛型了。
举例:<T>
就是泛型,(不一定非得叫 T
),设置泛型后即可在函数中使用 T
来表示该类型:
1 | function test<T>(arg: T): T { |
泛型可以写多个:
1 | function test<T, K>(a: T, b: K): K { |
类中同样可以使用泛型:
1 | class MyClass<T> { |
也可以对泛型的范围进行约束:
1 | interface Demo { |