为什么要学 TypeScript?
先聊 JavaScript 的一个老毛病。
我在网页上放了一个输入框,输入了 18,打算拿它做加法。结果一跑,发现 18 + 1 等于 "181"。没有报错,没有警告,程序安安静静地给出了一个错误答案。
这就是 JS 的弱类型问题。input.value 拿到的永远是字符串,而 + 这个符号在 JS 里既能做数字加法,也能做字符串拼接,全看两边是什么类型。所以 "18" + 1 它不崩溃,只是悄悄给你拼了个字符串。这类 bug 可以在系统里潜伏很久,很难排查。
TypeScript 就是来解决这个问题的。它是微软做的,本质上是 JS 的超集,意思是所有 JS 代码都是合法的 TS 代码,只是 TS 在此基础上加了类型约束。你可以给变量、函数参数和返回值标注类型,TS 在编译阶段就会帮你检查,把问题扼杀在运行之前。
typescript
const age: number = 123; // 明确告诉 TS:这是数字
const name: string = "9527"; // 这是字符串
function add(a: number, b: number): number {
return a + b;
}
如果不小心把字符串传进 add(),TS 编译时就会报错,而不是等到线上炸锅。这也是为什么 TS 现在已经是 AI Agent 开发的标配——越复杂的系统,越需要类型来兜底。
类型转换。如果从 input 拿到了字符串 "2",想把它变成数字,有几种写法:
typescript
Number("2") // 显式转换,推荐,最清晰
parseInt("2") // 也可以,常用于处理 "2px" 这类带单位的情况
+"2" // 隐式转换,能用但可读性差,不推荐
Promise 和 async/await:异步
JS 是单线程的,遇到耗时操作(比如网络请求、定时器)不会傻等,而是先去干别的,等结果回来再处理。这就是异步。
ES6 引入了 Promise,就像一张"承诺书":我现在给你一个 Promise,等任务完成了,我会兑现(resolve)或者告诉你失败了(reject)。
用 Promise 手写一个 sleep 函数:
javascript
function sleep(t) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(); // t 毫秒后兑现承诺
}, t);
});
}
但如果异步操作多了,Promise 嵌套起来会很难看。async/await 解决了这个问题,它让异步代码读起来像同步:
javascript
async function main() {
console.log('--start--');
await sleep(2000); // 在这里暂停 2 秒,再往下走
console.log('--end--');
}
await 后面接一个 Promise,程序会等它完成再继续。注意 await 只能在 async 函数内部使用。
Bun:比 Node 更快的运行时
写好了 TS 文件,得有个地方运行它。传统上用 Node.js,但现在有个更好的选择:Bun。
Bun 是一个更现代的 JS/TS 运行时,有几个特点值得记住:
- 原生支持 TypeScript,不需要手动配置编译,直接
bun run index.ts就能跑 - 速度快,底层用 Zig 语言写的,启动和执行都比 Node 快
- 内置包管理器,替代 npm,
bun install比npm install快得多 - 零配置,开箱即用,适合快速起项目
用 axios 调用 AI 接口
把上面的知识组合起来,可以写一个真正调用 LLM 接口的程序。
先说 HTTP 请求。调用 API 有 GET 和 POST 两种常见方式。对于 AI 接口,要用 POST,原因有两个:GET 请求的参数暴露在 URL 里,API Key 会明文可见;而且 GET 有长度限制,发不了太多内容。POST 把数据放在请求体(body)里,更安全、也没有大小限制。
axios 是一个封装了原生 fetch 的 HTTP 请求框架,企业项目里用得很多,写起来更简洁,错误处理也更完善。
typescript
import axios from 'axios';
import dotenv from 'dotenv';
dotenv.config(); // 读取 .env 文件里的环境变量
async function chat() {
try {
const res = await axios.post(
process.env.DEEPSEEK_BASE_URL, // 接口地址
{
model: 'deepseek-v4-flash',
messages: [{ role: 'user', content: '你好,介绍一下Bun' }]
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.DEEPSEEK_API_KEY}`
}
}
);
// axios 的响应会自动包一层 .data
console.log(res.data.choices[0].message.content);
} catch (err: any) {
console.log(err.message);
}
}
chat();
几个细节值得注意:
API Key 要放 .env 文件里,用 dotenv 读取,如果写在代码里,代码可能会传到 GitHub,Key 泄露就麻烦了。
一定要包 try/catch。调用 LLM 接口失败的可能性很多:网络超时、Key 无效、模型服务忙……不加错误处理,程序直接崩掉,什么信息都没有。
小结
这几个知识点串起来其实就是一条线:用 TypeScript 写出有类型保障的代码,用 async/await 处理异步的网络请求,用 axios 发送 HTTP POST 调用 AI 接口,用 Bun 直接运行整个项目,用 .env 保护敏感信息。
每一块单独看都不复杂,组合在一起就是一个完整的 AI Agent 最小骨架。