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 小时前
教育培训系统开发流程详解:平台建设关键环节解析
数据库·后端·学习
Java编程爱好者1 小时前
服务里的 Redis 锁惊群问题:一次本地合流优化实践
后端
Nturmoils1 小时前
线上修一批脏数据,先别急着全量重来
数据库·后端
飞天狗1111 小时前
零基础JavaWeb入门——第五课第一小节:九大内置对象 · 第1个:request(请求对象)
java·开发语言·前端·后端·servlet
码云骑士2 小时前
23-Django-ORM的N+1问题-select_related与prefetch_related详解
后端·python·django
掘金者阿豪3 小时前
当内容平台越来越多后,我决定把文章放回自己的地盘
后端
llz_1123 小时前
web-第六次课后作业
前端·spring boot·后端
何以解忧,唯有..3 小时前
Go语言类型转换详解:从基础到进阶实践
开发语言·后端·golang
爱勇宝3 小时前
CEO通知5100名员工:今年不涨薪了,钱要投给AI!
前端·后端·程序员