七、类型检查机制

# 七、类型检查机制
类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。 作用:辅助开发,提高开发效率。 类型检查机制通常有:
- 类型推断
- 类型兼容性
- 类型保护
# 类型推断
不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自动地为其推断出一个类型。 类型推断通常分为:
- 基础类型推断
- 最佳通用类型推断
- 上下文类型推断
/**
* 基础类型推断
*/
let a = 1
let b = [1]
// let c = (x = 1) => {}
let d = (x = 1) => x + 1
/**
* 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型
*/
// slet e = [1, null]
/**
* 上下文类型推断:从左往右进行推断,上面是从右往左进行推断
*/
window.onkeydown = (event) => {
// console.log(event.button)
}
/**
* 类型断言 as
* 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患
*/
interface Foo {
bar: number
}
// let foo = {} as Foo
// foo.bar = 1
let foo: Foo = {
bar: 1
}
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
27
28
29
30
31
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
27
28
29
30
31
# 类型兼容性
当一个类型Y可以被赋值给另一个类型X时,我们就可以说类型X兼容类型Y X兼容Y:X(目标类型) = Y(源类型) 口诀: 结构之间兼容: 成员少的兼容成员多的 函数之间兼容: 参数多的兼容参数少的
/**
* 基础类型推断
*/
let a = 1
let b = [1]
// let c = (x = 1) => {}
let d = (x = 1) => x + 1
/**
* 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型
*/
// slet e = [1, null]
/**
* 上下文类型推断:从左往右进行推断,上面是从右往左进行推断
*/
// window.onkeydown = (event) => {
// // console.log(event.button)
// }
/**
* 类型断言 as
* 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患
*/
interface Foo {
bar: number
}
// let foo = {} as Foo
// foo.bar = 1
let foo: Foo = {
bar: 1
}
/**
* 类型兼容
* X兼容Y:X(目标类型) = Y(源类型)
*/
// 关闭strictNullChecks时,字符串类型可以赋值null,这时,我们就可以说字符型兼容null类型
let s: string = 'a'
s = null
// 接口兼容性
// 成员少的兼容成员多的
interface X {
a: any;
b: any;
}
interface Y {
a: any;
b: any;
c: any;
}
let z: X = {a: 1, b: 2}
let y: Y = {a: 1, b: 2, c: 3}
x = y
// y = x
// 函数兼容性
type Handler = (a: number, b: number) => void
function hof(handler: Handler) {
return handler
}
// 1).参数个数:目标函数的参数个数要多于源函数的参数个数
let handler1 = (a: number) => {}
hof(handler1)
let handler3 = (a: number, b: number, c: number) => {}
// hof(handler3)
// 可选参数和剩余参数
// 关闭strictFunctionTypes,可以兼容
let a1 = (p1: number, p2: number) => {}
let b1 = (p1?: number, p2?: number) => {}
let c1 = (...args: number[]) => {}
a1 = b1
a1 = c1
b1 = c1
b1 = a1
c1 = a1
c1 = b1
// 2).参数类型
let handler4 = (a: string) => {}
// hof(handler4)
interface Point3D {
x: number;
y: number;
z: number;
}
interface Point2D {
x: number;
y: number;
}
let p3d = (point: Point3D) => {};
let p2d = (point: Point2D) => {};
p3d = p2d
// 关闭strictFunctionTypes可兼容以下
p2d = p3d
// 这种函数参数之间相互赋值的情况,叫做函数参数的双向协变
// 3).返回值类型
let h = () => ({name: 'Alice'});
let g = () => ({name: 'Alice', location: 'shanghai'});
h = g
// g = h
function overload1(a: number, b: number): number;
function overload1(a: string, b: string): string;
function overload1(a: any, b: any): any {};
// 枚举兼容性
enum Fruit { Apple, Banana }
enum Color { Red, Green }
let fruit: Fruit.Apple = 3
let no: number = Fruit.Apple
// 枚举之间是完全不兼容的
// let color: Color.Red = Fruit.Apple
// 类兼容性
// 如果类中含有私有成员,则这两种类就不兼容,只有父类和子类相互兼容
class J {
constructor(p: number, q: number) {}
id: number = 1
// private name: string = ''
}
class K {
static s = 1
constructor(p: number) {}
id: number = 2
}
let aa = new J(1,2);
let bb = new K(1);
aa = bb
bb = aa
class L extends J {}
let cc = new L(1, 2)
aa = cc
cc = aa
// 泛型兼容性
// 泛型接口中没有任何成员是可以相互兼容的
interface Empty<T> {
value: T
}
// let obj1: Empty<number> = {};
// let obj2: Empty<string> = {};
// obj1 = obj2
// 泛型函数的定义相同,但是没有指定类型参数,他们之间也是项目兼容的
let log3 = <T>(x: T): T => {
console.log('x')
return x
}
let log4 = <U>(y: U): U => {
console.log('y')
return y
}
log3 = log4
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 类型保护
TypeScript 能够在特定的区块中保证变量属于某种确定的类型。 可以在此区块中放心地引用此类型的属性,或者调用此类型的方法。
enum Type { Strong, Week }
class Java {
helloJava() {
console.log('hello Java')
}
java: any
}
class JavaScript {
helloJavaScript() {
console.log('hello JavaScript')
}
javascript: any
}
function isJava(lang: Java | JavaScript): lang is Java {
return (lang as Java).helloJava !== undefined
}
function getLanguage(type: Type, x: string | number) {
let lang = type === Type.Strong ? new Java() : new JavaScript()
// if ((lang as Java).helloJava) {
// (lang as Java).helloJava()
// } else {
// (lang as JavaScript).helloJavaScript()
// }
// instanceof
// if ( lang instanceof Java ) {
// lang.helloJava()
// } else {
// lang.helloJavaScript()
// }
// in
// if ('java' in lang) {
// lang.helloJava()
// } else {
// lang.helloJavaScript()
// }
// typeof
// if (typeof x === 'string') {
// x.length
// } else {
// x.toFixed(2)
// }
//
if(isJava(lang)) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
return lang
}
getLanguage(Type.Strong)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
上次更新: 2021/04/22, 00:08:06