前言

首先 TypeScript 是 JavaScript 的超集。在写图书管理系统的项目时,大部分使用的是 TypeScript 语言。毕竟是从零开始学的 TypeScript ,甚至 JavaScript 还没学明白就直接跑来写 TypeScript 了。在写的过程中经常会有许多的疑惑,决定写这篇文章记录下来。

type 关键字

首先看到下面这玩意就挺蒙的,到后面才知道这个 type 居然是个函数…
虽然知道箭头函数这个东西,但还是蒙的…

1
type RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;

type 基本语法和用法

这玩意基础语法非常简单:

1
type 类型别名 = 类型定义;

最基本的用法就如下,给基本类型取个别的名称:

1
2
3
4
5
6
7
// 给 string 起别名
type ID = string;
let userId: ID = "abc123";

// 联合字面量类型 (非常实用,模拟枚举)
type Status = "active" | "inactive" | "pending";
let currentStatus: Status = "active"; // 只能赋值这三个字符串之一

然后是定义联合类型,表示一个值可以是几种类型之一:

1
2
3
4
5
6
type StringOrNumber = string | number;

let value: StringOrNumber;
value = "hello"; // OK
value = 123; // OK
// value = true; // Error

既然有联合肯定有交叉:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Person = {
name: string;
};

type Employee = {
employeeId: string;
};

// Worker 同时拥有 Person 和 Employee 的属性
type Worker = Person & Employee;

let myWorker: Worker = {
name: "Bob",
employeeId: "E001"
};

定义数组和元组

1
2
3
4
5
6
7
// 数组
type NumberArray = number[];
let scores: NumberArray = [90, 85, 100];

// 元组 (固定长度和类型的数组)
type UserInfoTuple = [string, number];
let user: UserInfoTuple = ["Charlie", 30];

type 定义对象

这是 type 最常见的用法之一,用来描述一个对象里面有写啥参数:

1
2
3
4
5
6
7
8
9
10
11
12
type User = {
name: string;
age: number;
email?: string; // ? 表示可选属性
readonly id: number; // readonly 表示只读属性,创建后不可修改
};

let user1: User = {
id: 1,
name: "Alice",
age: 25,
};

type 定义函数类型

这个就是最初的疑惑了,type 可以用来定义函数的参数和返回值类型:

1
2
3
4
5
6
// 语法:type 别名 = (参数列表) => 返回值类型
type GreetFunction = (name: string) => string;

const greet: GreetFunction = (name) => {
return `Hello, ${name}`;
};

type 定义泛型类型

type 可以定义带有泛型参数的类型,增加类型的复用性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// T 是泛型参数,在具体使用时才确定类型
type ApiResponse<T> = {
code: number;
message: string;
data: T; // data 的类型由传入的 T 决定
};

// 使用时指定 T 为 string
let stringRes: ApiResponse<string> = {
code: 200,
message: "success",
data: "some string data"
};

// 使用时指定 T 为 User (结合前面定义的 User 类型)
let userRes: ApiResponse<User> = {
code: 200,
message: "success",
data: { name: "Dave", age: 40, id: 2 }
};

之前就有见到过 这个东西,完全看不懂,这里也是我第一次接触到泛型,写这段话时在解决如何消灭 any 这个类型的问题,好像就和泛型有关。

type 与 interface 的区别

不知道 (即答) (o′ω`o)ノ,写这段话时甚至 interface 都没用过呢 <(▰˘◡˘▰)>
但是查到的资料 (问AI) 上是这么写的,记录一下,以后用 interface 时来看一眼

AI 说: 在定义对象类型时,type 和 interface 非常相似,很多时候可以互换,但它们有核心区别

特性 type interface
核心定位 类型别名(给任何类型起名字) 接口(描述对象的形状)
对象扩展 使用交叉类型& 使用extends关键字
声明合并 不支持(同名type会报错) 支持(同名interface会自动合并,在扩展第三方库很有用)
联合/交叉类型 支持(type A = B 或 C) 不支持(不能写 interface A extends B 或 C)
基本类型别名 支持(type ID = String) 不支持
元组/函数 更简洁自然 也能定义,但语法稍显怪异

Promise 对象

我了个豆哪里蹦出来的 reslve 和 reject ?
好了这下知道了,这函数返回一个 promise ,而 JS 引擎自动提供的两个参数:resolve 和 reject 这俩回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function received(req: IncomingMessage): Promise<any> {
return new Promise((resolve, reject) => {
let buffer = Buffer.alloc(0);
req.on("data", (chunk) => {
buffer = Buffer.concat([buffer, chunk]);
});
req.on("end", () => {
try {
const body = buffer.toString();
resolve(JSON.parse(body));
} catch (e) {
reject(e);
}
});
req.on("error", reject);
});
}

async 异步编程

这里放上一段异步函数与同步函数的对比:

同步函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import time

def fetch_data(id):
print(f"开始获取数据 {id}...")
time.sleep(2) # 模拟网络请求阻塞 2 秒
print(f"数据 {id} 获取完毕")
return f"Result {id}"

def main():
start = time.time()
# 依次执行,总耗时 = 2 + 2 = 4 秒
result1 = fetch_data(1)
result2 = fetch_data(2)
print(f"总耗时: {time.time() - start:.2f} 秒")

main()

异步函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const sleep = (ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms));

async function fetchData (id: number): Promise<string> {
console.log(`正在获取数据${id}`);

await sleep(2000);

console.log(`获取数据${id}完毕`);
return `Result ${id}`;
}

async function main() {
const start = Date.now();
const results = await Promise.all([
fetchData(1),
fetchData(2)
]);
// 现在会耗时两秒钟
console.log(results);
console.log(`总耗时: ${((Date.now() - start) / 1000).toFixed(2)} 秒`);
}

main();

呃,JavaScript 是单线程,不支持直接阻塞,要完成阻塞还是得写 async 和 await 才能达成目的,看着很奇怪…
同步用 Python 贴出来算了…

创建 Promise 对象

手动创建一个 Promise 对象并在其他异步函数中获取它:

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
// 定义一个函数,返回一个 Promise
function fetchUserData(userId: string) {
return new Promise((resolve, reject) => {
// 这里通常放置耗时的异步操作,比如发网络请求、读文件等
console.log("开始请求服务器...");

setTimeout(() => { // 模拟网络延迟 2 秒
if (userId === "123") {
// 成功了:调用 resolve,把数据传出去
resolve({ name: "张三", age: 25 });
} else {
// 失败了:调用 reject,把错误信息传出去
reject(new Error("用户不存在"));
}
}, 2000);
});
}

// 在这里使用这个 Promise 对象
async function main() {
try {
// await 会暂停在这里,直到 Promise 的 resolve 触发,并拿到结果
const data = await fetchUserData("123");
console.log("成功了,数据是:", data);
} catch (error) {
// 如果 Promise 内部触发了 reject,就会跳到这里
console.log("失败了,错误是:", error.message);
}
}

结语

TypeScript 写起来确实舒服,比刚开始写 JavaScript 要舒服些。但是由于没有打好基础,写起来是真的艰难…

遇到问题就更新…