史上最强typescript入门

TypeScript简称TS,TS和JS之间的关系其实就是Less/Sass和CSS之间的关系

什么是typescript

typescript是javascript的超集,可以理解为它继承了javascript,并在javascript上实现了扩展

typescript有哪些特点

typescript提供了静态检测机制,可以在编译的时候发现错误
支持最新的javascript新特性
使javascript支持强数据类型

搭建typescript环境

1
2
3
4
5
npm i -g typescript   // 全局安装typescript
npm i -g ts-node
tsc --init // 初始化tsconfig.json配置文件

tsc index.ts // 把ts文件编译成js

js八种内置数据类型

1
2
3
4
5
6
7
8
9
// js八种内置类型
let u: undefined;
let n: null = null;
let bool: boolean = true;
let str: string = "abc";
let num: number = 10;
let obj: object = {};
// let big: bigint = 100n; // 提示失败,"ts找不到bigint"
let sym: symbol = Symbol();

null和undefined

null和undefined是所有类型的子类型(需要修改tsconfig.json中{strictNullChecks”:false})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let u: undefined;
let n: null = null;
let bool: boolean = true;
let str: string = "abc";
let num: number = 10;
let obj: object = {};
// let big: bigint = 100n;
let sym: symbol = Symbol();

// 可以把 null 和 undefined 赋值给其他类型,因为他们是所有类型的子类型
bool = null; // null可以赋值给布尔值
bool = undefined; // undefined可以赋值给布尔值

str = null;
str = undefined;

num = null;
num = undefined;

obj = null;
obj = undefined;

sym = null;
sym = undefined;

ps: 如果你在tsconfig.json指定了"strictNullChecks":true ,null 和 undefined 只能赋值给 void 和它们各自的类型。

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

// Array
// 对数组类型的定义有两种方式
let arr: string[] = ["a", "b"];
// arr = ["1", 2];

let arr1: Array<string> = ["a", "b"];

// 数组定义联合类型
let arr2: (number | string)[];
arr2 = ["a", 1, "b", 2];

// interface接口,定义新类型
interface Person {
name: string,
age: number
}
let arr3: Person[] = [{name: "alan", age: 10}];

// 函数
// 函数声明
function sum(x: number, y: number): number {
return x + y;
}

// 函数表达式, 定义函数表达式类型
let mySum: (x: number, y: number)=>number;
mySum = function(x: number, y: number) {
return x + y;
}

// 用接口定义函数类型
interface Isearch {
(source: string, substring: string): boolean;
}

let fn: Isearch; // 使用Isearch函数类型限制fn
fn = function(x: string, y: string) {
return true;
}

// ?(问号)表示可选参数 和参数默认值
function buildName(firstName: string = "hello", lastName?: string): string { // 有默认值参数也是可选参数
if(lastName) {
return firstName + " " + lastName;
} else {
return firstName;
}
}
let tname = buildName("alan", "liang");
let tom = buildName();

`ps: 可选参数后面不允许再出现必须参数`

// 剩余参数
function push(arr: any[], ...items: any[]): void {
items.forEach(function(item: any){
arr.push(item);
});
}
let arr: any[] = [];
push(arr, 1, 2, 3);
console.log(arr); // [1, 2, 3]


// 函数重载
function add(x: any, y: any): number { // any支持数字和字符串
return x + y;
}
console.log(add(1, 3));
console.log(add("a", "b"));

type Combinable = string | number;

function add1(x: Combinable, y: Combinable): Combinable {
if(typeof x === 'string' || typeof y === "string") { // 使用“+”号运算符,只要x,y一个是字符串,就使用字符串连接
return x.toString() + y.toString()
}
return x + y;
}
console.log(add1(1, 3));
console.log(add1("a", "b"));
let result: Combinable = add1("a", "b");
// result.split(""); // number上不存在属性split

// 函数重载
type Types = number | string;
function addNum(a: number, b: number): number;
function addNum(a: string, b: string): string;
function addNum(a: number, b: string): string;
function addNum(a: string, b: number): string;
function addNum(a: Types, b: Types): Types { // 必须要实现
if(typeof a === 'string' || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
};
let res = addNum('apple', 'banana'); // 调用的是function addNum(a: string, b: string): string;
res.split(""); // res是字符串,所有ts不会提示


// tuple 元组,在单个变量中存储不同的数据类型,可以限制数组元素的个数和类型
let x: [string, number];
x = ["a", 1]; // ok

// 元祖类型的解构赋值
let employee: [number, string] = [1, "alan"];
let [id, username] = employee;
console.log(`id: ${id}`); // 1
console.log(`username: ${username}`); // alan

let employee1: [number, string] = [1, "alan"];
// let [id1, username1, age1] = employee1; // 提示跟数组定义长度不一致


// 元组类型的可选元素
let optionalTuple: [string, number?];
optionalTuple = ["alan", 2];
console.log(optionalTuple); // ["alan", 2]
optionalTuple = ["alan"];
console.log(optionalTuple); // ["alan"]

// 可选元素坐标表示
type Point = [number, number?, number?];
const x: Point = [10]; // 一维坐标
const y: Point = [20, 21]; // 二维坐标
const z: Point = [30, 31, 32]; // 三维坐标


// 元祖类型的剩余元素
type RestTupleType = [number, ...string[]];
let restTuple: RestTupleType = [2, "apple", "banana", "pineapple"];
console.log(restTuple[0]); // 2
console.log(restTuple[1]); // apple


// 只读的元组类型
const point: readonly [number, number] = [10, 20];
// point[0] = 12; // 只读属性不能重新赋值
// point.push(12); // 只读属性不能重新赋值
// point.pop(); // 只读属性不能重新赋值
// point.splice(1, 1); // 只读属性不能重新赋值

// void 表示没有任何类型
let a: void;
let b: number = a; // 不能将void分配给number

// 方法返回值是undefined,需要定义成void
function fn(): undefined { // 错误,需要定义为void

}

// never 永不存在的值类型,是任何类型的子类型,如:函数抛出异常或者死循环
function err(msg: string): never { // 函数抛出异常定义返回值类型为never
throw new Error(msg);
}
function loopForever(): never { // 死循环定义返回值类型为never
while(true) {}
}

// 没有任何类型可以赋值给never类型
let ne: never;
let nev: never = (()=> {throw new Error("err")})();
let an: any;
// ne = 10; // 不能将number赋值给never类型
ne = nev; // never本身可以赋值给never类型
// ne = an; // 不能将any赋值给never类型

// 定义安全代码
type Foo = string | number;
function withNever(foo: Foo) {
if(typeof foo === "string") { // 处理字符串
} else if(typeof foo === "number") { // 处理数字
} else { // 处理never
const check: never = foo; // 新增联合类型没有对应的实现会产生编译错误, 这段代码是安全的
}
}

// any类型允许被赋值为任意类型
let a: any = 10;
a = "alan";
a = false;
a = undefined;
a = null;
a = [];
a = {};

let anyThing: any = "hello";
console.log(anyThing.myName);
// console.log(anyThing.myName.firstName);
let any2: any = "world";
any2.setName("alan");

let something; // 默认为any类型
something = "something";

// unknown 任何类型都可以分配给unknown, unknown类型只能赋值给unknown和any
let unk: unknown = 2;
let uncertain: any = unk; // unknown可以赋值给any
let un: unknown = unk; // unknown可以赋值给unkown
// let num: number = unk; // unknown不可以赋值给number

function hello() {
return "abc";
}
const dog: unknown = { hello: hello};
// dog.hello(); // error错误, unknown类型无法调用属性或者方法,可以使用类型断言

function world() {
let x: unknown;
return x;
}

const x = world();
const word = x.toLowerCase();

if(typeof x === "string") {
const x1 = x.toLowerCase(); // 字符串肯定有toLowerCase方法
}

// 类型断言
const y = (x as string).toLowerCase(); // 断言字符串编译不会报错


// Number, String, Boolean, Symbol与ts基本类型的区别
let num: number = 10; // 原始类型
let Num: Number = 20; // 对象类型

Num = num; // ok 原始类型(number)兼容对象类型(Number)
num = Num; // ts error 对象类型(Number)不兼容原始类型

// 对比object, Object和{}
// object代表所有非原始类型
let lowerObj: object;
lowerObj = 1; // error
lowerObj = "a"; // error
lowerObj = true; // error
lowerObj = undefined; // error
lowerObj = null; // error
lowerObj = {}; // ok

let upperObj: Object; // 所有原始类型,非原始类型都可以赋值给Object类型。除了严格模式下null和undefined
upperObj = 1; // ok
upperObj = "a"; // ok
upperObj = true; // error
upperObj = undefined; // error 严格模式下报错
upperObj = null; // error 严格模式下报错
upperObj = {}; // ok

// 大 Object 不仅是小 object 的父类型,同时也是小 object 的子类型
type objlowerExtendsObj = object extends Object ? true : false; // true
type ObjExtendsLowerobj = Object extends object ? true : false; // true
let lowerCaseObject: object; // 定义原始类型object
let upperCaseObject: Object={}; // 定义Object对象类型
lowerCaseObject = upperCaseObject; //
upperCaseObject = lowerCaseObject;

// 结论:{}、大 Object 是比小 object 更宽泛的类型(least specific),{} 和大 Object 可以互相代替,用来表示原始类型(null、undefined 除外)和非原始类型;而小 object 则表示非原始类型。