Bun + TypeScript 后端入门:从类型约束到 LLM API 调用

Bun + TypeScript 后端入门全记录:从类型约束到 LLM API 调用

一份零基础后端学习笔记,覆盖 Bun 运行时、TypeScript 类型系统、HTTP 请求封装,以及用 Axios 调用大模型接口的完整流程。


目录

  • [1. Bun:不只是更快的 Node.js](#1. Bun:不只是更快的 Node.js "#1-bun%E4%B8%8D%E5%8F%AA%E6%98%AF%E6%9B%B4%E5%BF%AB%E7%9A%84-nodejs")
    • [1.1 Bun 是什么](#1.1 Bun 是什么 "#11-bun-%E6%98%AF%E4%BB%80%E4%B9%88")
    • [1.2 Bun 的三重身份](#1.2 Bun 的三重身份 "#12-bun-%E7%9A%84%E4%B8%89%E9%87%8D%E8%BA%AB%E4%BB%BD")
    • [1.3 Bun 与 Anthropic / Claude Code](#1.3 Bun 与 Anthropic / Claude Code "#13-bun-%E4%B8%8E-anthropic--claude-code")
    • [1.4 安装 Bun](#1.4 安装 Bun "#14-%E5%AE%89%E8%A3%85-bun")
  • [2. TypeScript:给 JavaScript 装上类型锚点](#2. TypeScript:给 JavaScript 装上类型锚点 "#2-typescript%E7%BB%99-javascript-%E8%A3%85%E4%B8%8A%E7%B1%BB%E5%9E%8B%E9%94%9A%E7%82%B9")
    • [2.1 JavaScript 的"弱类型"之痛](#2.1 JavaScript 的"弱类型"之痛 "#21-javascript-%E7%9A%84%E5%BC%B1%E7%B1%BB%E5%9E%8B%E4%B9%8B%E7%97%9B")
    • [2.2 TypeScript 如何解决问题](#2.2 TypeScript 如何解决问题 "#22-typescript-%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%E9%97%AE%E9%A2%98")
    • [2.3 基础类型注解](#2.3 基础类型注解 "#23-%E5%9F%BA%E7%A1%80%E7%B1%BB%E5%9E%8B%E6%B3%A8%E8%A7%A3")
    • [2.4 函数签名中的类型约束](#2.4 函数签名中的类型约束 "#24-%E5%87%BD%E6%95%B0%E7%AD%BE%E5%90%8D%E4%B8%AD%E7%9A%84%E7%B1%BB%E5%9E%8B%E7%BA%A6%E6%9D%9F")
    • [2.5 AI 时代为什么 TypeScript 成了主流](#2.5 AI 时代为什么 TypeScript 成了主流 "#25-ai-%E6%97%B6%E4%BB%A3%E4%B8%BA%E4%BB%80%E4%B9%88-typescript-%E6%88%90%E4%BA%86%E4%B8%BB%E6%B5%81")
  • [3. 类型转换实战:三种方式把字符串变成数字](#3. 类型转换实战:三种方式把字符串变成数字 "#3-%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E5%AE%9E%E6%88%98%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%8A%8A%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8F%98%E6%88%90%E6%95%B0%E5%AD%97")
    • [3.1 Number():显式构造函数](#3.1 Number():显式构造函数 "#31-number%E6%98%BE%E5%BC%8F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0")
    • [3.2 parseInt():解析整数](#3.2 parseInt():解析整数 "#32-parseint%E8%A7%A3%E6%9E%90%E6%95%B4%E6%95%B0")
    • [3.3 一元加运算符 +:隐式转换](#3.3 一元加运算符 +:隐式转换 "#33-%E4%B8%80%E5%85%83%E5%8A%A0%E8%BF%90%E7%AE%97%E7%AC%A6-%E9%9A%90%E5%BC%8F%E8%BD%AC%E6%8D%A2")
    • [3.4 三种方式的对比](#3.4 三种方式的对比 "#34-%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%E7%9A%84%E5%AF%B9%E6%AF%94")
  • [4. 浏览器中的类型陷阱:一个 Input 事件的教训](#4. 浏览器中的类型陷阱:一个 Input 事件的教训 "#4-%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E7%9A%84%E7%B1%BB%E5%9E%8B%E9%99%B7%E9%98%B1%E4%B8%80%E4%B8%AA-input-%E4%BA%8B%E4%BB%B6%E7%9A%84%E6%95%99%E8%AE%AD")
  • [5. 封装异步工具:手写 sleep 函数](#5. 封装异步工具:手写 sleep 函数 "#5-%E5%B0%81%E8%A3%85%E5%BC%82%E6%AD%A5%E5%B7%A5%E5%85%B7%E6%89%8B%E5%86%99-sleep-%E5%87%BD%E6%95%B0")
  • [6. HTTP 请求:从 fetch 到 axios](#6. HTTP 请求:从 fetch 到 axios "#6-http-%E8%AF%B7%E6%B1%82%E4%BB%8E-fetch-%E5%88%B0-axios")
    • [6.1 GET 请求的局限](#6.1 GET 请求的局限 "#61-get-%E8%AF%B7%E6%B1%82%E7%9A%84%E5%B1%80%E9%99%90")
    • [6.2 POST 请求的结构](#6.2 POST 请求的结构 "#62-post-%E8%AF%B7%E6%B1%82%E7%9A%84%E7%BB%93%E6%9E%84")
    • [6.3 fetch vs axios:原生 API 与封装框架的差距](#6.3 fetch vs axios:原生 API 与封装框架的差距 "#63-fetch-vs-axios%E5%8E%9F%E7%94%9F-api-%E4%B8%8E%E5%B0%81%E8%A3%85%E6%A1%86%E6%9E%B6%E7%9A%84%E5%B7%AE%E8%B7%9D")
  • [7. 实战:用 Bun + Axios 调用 DeepSeek 大模型](#7. 实战:用 Bun + Axios 调用 DeepSeek 大模型 "#7-%E5%AE%9E%E6%88%98%E7%94%A8-bun--axios-%E8%B0%83%E7%94%A8-deepseek-%E5%A4%A7%E6%A8%A1%E5%9E%8B")
    • [7.1 项目初始化](#7.1 项目初始化 "#71-%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96")
    • [7.2 环境变量管理](#7.2 环境变量管理 "#72-%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E7%AE%A1%E7%90%86")
    • [7.3 编写请求代码](#7.3 编写请求代码 "#73-%E7%BC%96%E5%86%99%E8%AF%B7%E6%B1%82%E4%BB%A3%E7%A0%81")
    • [7.4 逐行拆解](#7.4 逐行拆解 "#74-%E9%80%90%E8%A1%8C%E6%8B%86%E8%A7%A3")
    • [7.5 运行与调试](#7.5 运行与调试 "#75-%E8%BF%90%E8%A1%8C%E4%B8%8E%E8%B0%83%E8%AF%95")
  • [8. 总结](#8. 总结 "#8-%E6%80%BB%E7%BB%93")
  • 感谢阅读

1. Bun:不只是更快的 Node.js

1.1 Bun 是什么

Bun 是一个JavaScript / TypeScript 运行时,由 Jarred Sumner 使用 Zig 语言从零编写。它的设计目标很直白------做一个比 Node.js 更快、更现代、且开箱即用的替代品。

如果你写过 Node.js,你一定经历过这些事:装 nodemon 做热重载、装 ts-nodetsx 跑 TypeScript、装 dotenv 读环境变量、面对 node_modules 黑洞般的体积叹气。Bun 把这些痛点打包解决掉了------它原生支持 TypeScript,内置文件监听热重载,自带 .env 解析,包安装速度比 npm 快一个数量级。

性能方面,Bun 使用 JavaScriptCore(Safari 的 JS 引擎)替代 V8,启动速度极快,尤其适合短生命周期任务(如 Serverless 函数、脚本工具)。

1.2 Bun 的三重身份

Bun 同时扮演三个角色:

角色 对标工具 说明
运行时 Node.js 执行 JS/TS 代码,提供标准 API
包管理器 npm / yarn / pnpm bun install 安装依赖,速度更快
打包器 Webpack / esbuild bun build 打包项目,原生速度

你不需要分别安装运行环境和包管理工具,一个 bun 命令全部搞定。

1.3 Bun 与 Anthropic / Claude Code

2025 年底,Anthropic 收购了 Bun 的开发团队 Oven。这意味着 Bun 的底层技术被直接用于 Claude Code 的运行环境。当你使用 Claude Code 执行代码时,底层跑的可能就是 Bun。这一收购也说明了 Bun 在 AI 工具链中的战略地位------AI Agent 需要快速启动、快速执行、快速迭代的运行环境,而 Bun 恰好擅长这些。

1.4 安装 Bun

Windows 下通过 PowerShell 安装:

powershell 复制代码
powershell -c "irm bun.sh/install.ps1 | iex"

macOS / Linux:

bash 复制代码
curl -fsSL https://bun.sh/install | bash

安装完成后用 bun --version 验证。


2. TypeScript:给 JavaScript 装上类型锚点

2.1 JavaScript 的"弱类型"之痛

JavaScript 是弱类型语言,变量的类型在运行时可以随意变化。这带来了灵活性,也埋下了无数 bug。来看一个经典场景:

javascript 复制代码
const a = 1;
const b = "2";
console.log(a + b); // "12" ------ 字符串拼接,不是数学加法

+ 运算符在 JS 里有双重含义:数学加法和字符串拼接。当一侧操作数是字符串时,JS 会把另一边也转成字符串然后拼接。这个行为不会报错,所以你得不到任何异常提示------代码安静地产出了一个错误结果。在大项目中,这种静默的类型错误追查成本极高。

另一个常见陷阱在浏览器里:用户输入框的值永远是字符串,即使你期望的是一个数字。

html 复制代码
<input type="number" id="age">
<script>
  const age = document.getElementById("age").value; // 类型是 string,不是 number
  console.log(age + 1); // "181" 而非 19
</script>

2.2 TypeScript 如何解决问题

TypeScript 是微软开发的 JavaScript 超集 ------所有合法的 JS 代码都是合法的 TS 代码,但 TS 额外增加了一层类型系统

核心思路是:在编译阶段就发现问题,而不是等到运行时爆炸

TypeScript 代码需要编译成 JavaScript 才能运行。编译过程做了两件事:

  1. 类型检查:扫描代码中的类型错误,不符合约束的直接报错
  2. 代码转换:移除类型注解,输出纯 JavaScript

关键一点:编译后的 JS 代码里没有任何 TypeScript 依赖,运行时开销为零。

2.3 基础类型注解

TypeScript 的类型注解写在变量名后面,用冒号分隔:

typescript 复制代码
const nickname: string = "9527";
const age: number = 18;
console.log(`我是 ${nickname},今年 ${age} 岁`);

这行代码告诉编译器三件事:

  • nickname 只能是 string
  • age 只能是 number
  • 如果有人给 age 赋了一个字符串,编译器直接拒绝

类型注解不是强制的------TS 有类型推断能力,很多场景下你不写注解它也能自动推出来。但显式写出来,相当于给代码加了文档,AI 和人类读者都更容易理解意图。

2.4 函数签名中的类型约束

函数的参数和返回值也可以标注类型:

typescript 复制代码
function add(a: number, b: number): number {
    return a + b;
}

这里的含义:

  • a: number --- 参数 a 必须是数字
  • b: number --- 参数 b 必须是数字
  • ): number --- 返回值必须是数字

如果你尝试传入字符串,编辑器会在你保存文件之前就标红。TypeScript 的静态检查让"类型不对"这个类别的 bug 在编码阶段就被消灭。

2.5 AI 时代为什么 TypeScript 成了主流

当下几乎所有主流 AI 编码工具(Claude Code、GitHub Copilot、Cursor 等)都以 TypeScript 作为一等公民。原因有三:

  1. 类型信息是 AI 的说明书。AI 模型读代码时,类型注解告诉它每个变量是什么、函数接收什么返回什么,大幅减少理解偏差。
  2. 类型约束缩小了生成空间。AI 生成代码时有了类型约束,产出更精确,幻觉更少。
  3. 编译期错误拦截降低了 AI 代码的风险。即使用 AI 生成了类型不匹配的代码,编译器也会立刻拦住,形成了"AI 生成 → TS 编译检查 → 人工审核"的安全链路。

换句话说,TypeScript 不仅是给人用的,更是给 AI Agent 用的------复杂的项目中,类型系统是管理庞大数据结构的基础设施。


3. 类型转换实战:三种方式把字符串变成数字

在实际开发中,"外部数据是字符串,内部需要数字" 的场景非常频繁。下面用一段代码演示三种转换方式。

typescript 复制代码
let a: number = 1;
let b: string = '2';

// 方式一:Number() 构造函数
console.log(add(a, Number(b)));   // 3 ✅

// 方式二:parseInt() API
console.log(add(a, parseInt(b))); // 3 ✅

// 方式三:一元加运算符(隐式转换)
console.log(add(a, +b));          // 3 ✅

3.1 Number():显式构造函数

Number(value) 把任意值转成数字类型。规则清晰:能转就转,转不了返回 NaN

typescript 复制代码
Number('2');       // 2
Number('2.5');     // 2.5
Number('abc');     // NaN
Number(true);      // 1
Number(false);     // 0
Number(null);      // 0
Number(undefined); // NaN

适用场景:需要转换小数、布尔值等任意类型到数字时。这是最通用的方式。

3.2 parseInt():解析整数

parseInt(string, radix) 从字符串开头逐个字符解析,遇到非数字字符就停止。

typescript 复制代码
parseInt('2');      // 2
parseInt('2.9');    // 2(直接截断,不舍入)
parseInt('10px');   // 10(遇到 'p' 停止)
parseInt('abc');    // NaN(第一个字符就不是数字)
parseInt('0xFF');   // 255(自动识别十六进制)

注意 :始终传第二个参数 radix,避免意外行为。

typescript 复制代码
parseInt('08', 10);  // 8,明确指定十进制
parseInt('0x10', 16); // 16,十六进制

适用场景 :从带单位的字符串里提取整数,如 "10px"10

3.3 一元加运算符 +:隐式转换

在变量前加一个 + 号,本质上调用的是 ToNumber 内部操作,效果和 Number() 几乎一致。

typescript 复制代码
+'2';       // 2
+'2.5';     // 2.5
+'abc';     // NaN
+true;      // 1

优点:写法最简洁,常用于快速转换。

缺点 :代码意图不够显式,不熟悉的人可能疑惑 "为什么前面有个加号"。如果你的团队规范要求代码可读性优先,建议用 Number() 替代。

3.4 三种方式的对比

方式 小数支持 非纯数字字符串 可读性 推荐场景
Number() 返回 NaN ⭐⭐⭐ 通用转换,最推荐
parseInt() ❌ 截断 逐个解析,遇非数字停止 ⭐⭐ 提取整数("10px" 等)
+ 返回 NaN 快速转换,团队风格允许时使用

4. 浏览器中的类型陷阱:一个 Input 事件的教训

来看一段看似无害的 HTML + JS 代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text" id="ipt">
    <script>
        const ipt = document.getElementById("ipt");
        ipt.addEventListener("change", function () {
            console.log(event.target.value, typeof event.target.value);
        })
    </script>
</body>
</html>

这段代码的日志输出会让你意外------无论 <input>type 属性是 "text" 还是 "number"event.target.value 返回的始终是 string

javascript 复制代码
// 用户在输入框输入 123
console.log(typeof event.target.value); // "string",不是 "number"

这是因为 HTML 规范定义 input.value 就是字符串类型,type="number" 只在 UI 层限制了输入键盘和表单验证,并不改变底层 DOM API 的返回类型。

如果你直接用这个值做数学运算:

javascript 复制代码
const price = document.getElementById("price").value; // "100"
const total = price * 1.1; // 110,意外的正确------因为 * 运算符强制触发数字转换
const sum = price + 10;    // "10010" ------ 字符串拼接!

*-/ 运算符只有数学含义,会自动把字符串转成数字;但 + 同时有字符串拼接的含义,导致结果不可预期。这就是 TypeScript 要消灭的"隐式行为 bug"------如果你在 TS 中给 add(a: number, b: number) 传入 event.target.value,编译器会直接报错,因为你试图把 string 传给 number

教训:永远不要信任 DOM 的输入类型,拿到值后先做显式转换。


5. 封装异步工具:手写 sleep 函数

JavaScript 里没有原生的 sleep(),但可以用 Promise 封装一个:

javascript 复制代码
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
    console.log('--start--');
    await sleep(2000);  // 暂停 2 秒
    console.log('--end--');
}

拆解这段代码:

  1. new Promise(resolve => ...):创建一个 Promise 对象。Promise 是 JS 异步的核心抽象------代表一个"未来会完成"的操作。
  2. setTimeout(resolve, ms)ms 毫秒后调用 resolve,也就是告诉 Promise "我完成了"。
  3. await sleep(2000)await 暂停当前 async 函数的执行,直到 Promise 完成。期间 JS 引擎不会阻塞,可以去处理其他任务。

这个模式在调用 LLM API 时特别有用------比如请求频率限制时需要等待,或者轮询异步任务结果时需要间隔。


6. HTTP 请求:从 fetch 到 axios

6.1 GET 请求的局限

HTTP GET 请求把参数拼接在 URL 里:

ini 复制代码
https://api.example.com/chat?message=hello&apikey=sk-xxxxx

这带来了几个问题:

  • API Key 暴露在 URL 中。URL 会被浏览器历史记录、服务器日志、代理服务器完整记录,第三方拿到 URL 就拿到了你的密钥。
  • 长度限制。URL 有最大长度限制(浏览器通常是 2048 字符,不同服务器实现差异很大),发送长文本(比如一篇完整的对话上下文)会超出限制。
  • 语义不匹配。GET 的语义是"获取资源",不应该产生副作用。但调用 LLM 显然有副作用。

6.2 POST 请求的结构

POST 请求把数据放在请求体(body)里,URL 保持干净:

bash 复制代码
POST https://api.deepseek.com/v1/chat/completions
Content-Type: application/json
Authorization: Bearer sk-xxxxx

{"model": "deepseek-v4-pro", "messages": [...]}

HTTP 请求报文由三部分组成:

部分 内容 示例
请求行 Method + URL + HTTP 版本 POST /v1/chat/completions HTTP/1.1
请求头 元信息:内容类型、认证、缓存控制等 Content-Type: application/json
请求体 实际数据(GET 请求没有这一部分) JSON 字符串

6.3 fetch vs axios:原生 API 与封装框架的差距

浏览器提供了 fetch() API 发送 HTTP 请求,但它非常底层:

javascript 复制代码
// 原生 fetch ------ 需要手动处理每一步
fetch('https://api.example.com/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer xxx' },
    body: JSON.stringify({ message: 'hello' })
})
.then(res => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();  // 手动解析 JSON
})
.then(data => console.log(data))
.catch(err => console.error(err));

axios 在 fetch 之上做了封装:

javascript 复制代码
// axios ------ 自动处理 JSON 和错误
const res = await axios.post('https://api.example.com/chat',
    { message: 'hello' },                    // 自动 JSON.stringify
    { headers: { 'Authorization': 'Bearer xxx' } }
);
console.log(res.data);                        // 自动 JSON.parse
特性 fetch axios
JSON 自动序列化 ❌ 需手动 JSON.stringify ✅ 自动
JSON 自动解析 ❌ 需手动 .json() res.data 直接可用
错误状态码处理 ❌ 4xx/5xx 不会 reject ✅ 自动抛异常
请求拦截器
响应拦截器
超时设置 ❌ 需 AbortController { timeout: 5000 }

对于调用 LLM API 这种场景,axios 省去了大量样板代码,这也是为什么大多数后端项目选择 axios 而非裸 fetch。


7. 实战:用 Bun + Axios 调用 DeepSeek 大模型

这是笔记中最完整的实战代码,演示了从零搭建一个调用 LLM 的后端脚本。

7.1 项目初始化

bash 复制代码
mkdir axios-demo && cd axios-demo
bun init                              # 初始化 Bun 项目
bun add axios dotenv                  # 安装依赖
bun add -d @types/node               # 安装 Node 类型定义(开发依赖)

Bun 的包安装速度非常快------因为 Bun 的包管理器也是用 Zig 写的,比 npm 的 JS 实现快一个数量级。

7.2 环境变量管理

创建 .env 文件存储敏感信息:

env 复制代码
llm_api_url=https://api.deepseek.com/v1/chat/completions
llm_api_key=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx

注意.env 文件一定不能提交到 Git。项目的 .gitignore 中应该有:

bash 复制代码
.env
.env.local
.env.*.local

原因很简单:API Key 等于你的钱包钥匙,泄露后别人可以盗刷你的额度。

7.3 编写请求代码

typescript 复制代码
import axios from "axios";
import dotenv from "dotenv";

dotenv.config();  // 加载 .env 文件到 process.env

async function chat() {
    try {
        const res = await axios.post(
            `${process.env.llm_api_url}`,          // 第1个参数:URL
            {                                        // 第2个参数:请求体
                model: 'deepseek-v4-pro',
                messages: [
                    { role: 'user', content: '介绍一下bun' }
                ]
            },
            {                                        // 第3个参数:请求配置
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${process.env.llm_api_key}`
                }
            }
        );

        console.log(res.data.choices[0].message.content);
    } catch (error) {
        console.log(error.message);
    }
}

chat();

7.4 逐行拆解

import axios from "axios"

导入 axios 库。Bun 原生支持 ES Module 的 import 语法,不需要配置 "type": "module"

import dotenv from "dotenv"

导入 dotenv 库。调用 dotenv.config() 后,.env 文件中的键值对会被注入到 process.env 对象中。之后可以通过 process.env.llm_api_url 访问。

axios.post(url, data, config)

axios 的 POST 方法接收三个参数:

  • url:请求地址。这里从环境变量读取,方便切换不同 LLM 服务商(OpenAI / DeepSeek / 本地模型等)。
  • data:请求体对象。axios 自动将其序列化为 JSON 字符串。
  • config:请求配置。在这里设置了两个关键 header。

Content-Type: application/json

告诉服务器"我发过来的请求体是 JSON 格式"。服务器收到后会按 JSON 解析,而不是当成表单或纯文本。

Authorization: Bearer ${process.env.llm_api_key}

Bearer Token 认证。Bearer 是"持有者"的意思------谁持有这个 Token,谁就拥有对应的访问权限。API Key 从环境变量读取,绝不硬编码在代码里。

res.data.choices[0].message.content

OpenAI 兼容接口的响应结构:

less 复制代码
res.data                          // 整个响应体
  └── choices: []                 // 模型返回的候选回复列表(通常取第一个)
       └── [0]
            └── message: {}       // 消息对象
                 └── content: ""  // 模型回复的文本内容

理解这个嵌套结构,你就能从任何 OpenAI 兼容接口(DeepSeek、通义千问、GLM 等)中提取回复文本。

try...catch 错误处理

网络请求可能失败:网络断开、API Key 过期、服务商限流、参数错误......try...catch 确保这些情况不会导致程序崩溃,而是输出可读的错误信息。

7.5 运行与调试

bash 复制代码
bun run index.ts

如果一切正常,终端会输出 DeepSeek 模型对 "介绍一下bun" 的回答。如果出错,catch 块会打印错误原因,帮助你排查。


8. 总结

这篇文章从零开始,串起了 Bun 后端开发的一条完整链路:

  1. Bun 作为下一代 JS/TS 运行时,凭借速度和开箱即用特性,正在成为 AI 工具链的基础设施。
  2. TypeScript 的类型系统在编译阶段拦截类型错误,从根本上消灭了 JS 弱类型带来的静默 bug。
  3. 类型转换Number()parseInt()+)各有适用场景,理解它们的差异能写出更健壮的代码。
  4. DOM API 的类型陷阱提醒我们:外部输入永远不可信,必须做显式转换。
  5. Promise + setTimeout 封装异步等待,是调用 LLM API 的基础工具。
  6. POST vs GET 的选择关乎安全性和数据容量,API 调用场景中 POST 是正确答案。
  7. axios 封装省去了 fetch 的样板代码,自动处理 JSON 和错误,大幅提升开发效率。
  8. 环境变量管理是安全底线,API Key 绝不能出现在代码仓库里。

这些概念单独看都不复杂,但组合起来就是一条完整的后端开发工作流------从理解运行时、编写类型安全的代码,到发送 HTTP 请求调用大模型接口,每一步都不可或缺。


感谢阅读

如果这篇文章对你理解 Bun 和 TypeScript 后端开发有帮助,欢迎点赞、收藏、关注。我会持续记录和分享后端学习路上的实战笔记,一起进步!

相关推荐
易协同低代码1 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo1 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志2 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..2 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects2 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰2 小时前
一些基础和问题解决
后端
陈随易2 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN2 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana2 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端
学渣超2 小时前
记一次分布式事务数据不一致的排查之旅:从超时到索引,层层剥茧
java·后端·架构