前端进阶:Bun + TypeScript 从入门到调通第一个 LLM 接口

0 阅读4分钟

开篇

2025 年,Anthropic 做了一个让前端圈震动的决定——收购 Bun,将其作为 Claude Code 的底层运行时。这不是「又一个 JS 运行时」的噱头,而是真金白银的战略选择。为什么是 Bun?它和我们每天都在写的 Node.js 到底有什么区别?这篇文章带你从零开始,用 Bun + TypeScript 调通第一个大模型接口。


一、Bun 是什么?

一句话:Bun 是比 Node.js 更快、开箱即用、零配置的 JavaScript/TypeScript 运行时 + 包管理器。

用 Node.js 开发过项目的同学都懂——安装 ts-node、配置 tsconfig.json、等 npm install 跑到天荒地老……这些痛点 Bun 全帮你干掉了:

特性Node.jsBun
TypeScript 支持需要额外配置原生支持,直接运行 .ts 文件
包管理器npm / yarn / pnpm内置,速度碾压 npm
启动速度一般极快(基于 JavaScriptCore)
打包需要 webpack/esbuild内置 bundler

安装

Windows 下一条命令搞定:

powershell -c "irm bun.sh/install/windows | iex"

安装完成后,验证一下:

bun --version

二、为什么 TypeScript 是 AI Agent 时代的标配?

JavaScript 的「弱类型之痛」

来看一个真实的坑。写一个简单的加法函数:

function add(a, b) {
    return a + b;
}

add(1, "2");  // 结果:"12" 😱

你没看错——1 + "2" 在 JS 里是字符串拼接,返回 "12" 而不是 3不报错、不警告,错误可能藏在系统里很久才炸。

再比如浏览器输入框:

<input type="text" id="ipt">

<script>
    const ipt = document.getElementById("ipt");
    ipt.addEventListener("change", function(event) {
        console.log(event.target.value, typeof event.target.value);
        // 输出: "123" string  ← 你以为它是数字,其实永远是字符串!
    })
</script>

TypeScript 如何解决?

// 给参数加上类型约束
function add(a: number, b: number): number {
    return a + b;
}

// add(1, "2");  // ❌ 编译报错!在写代码阶段就拦截了 bug

// 正确的做法:显式类型转换
let a = 1;
let b = "2";
let c: number = add(a, Number(b));  // ✅ 3

TypeScript 做了三件事:

  1. 静态类型检查——编译阶段发现类型错误,不用等到运行时爆炸
  2. 更好的 IDE 体验——智能提示、自动补全、重构支持
  3. 代码即文档——类型定义本身就是最好的注释

如今 Claude Code、Cursor、Copilot 等 AI 编程工具生成的代码,TypeScript 已经是默认语言。强类型让 AI 更容易理解你的意图,生成的代码也更可靠。


三、实战:用 Bun + TypeScript 调用 LLM 接口

光说不练假把式。我们来搭一个完整的 Bun 项目,调用 DeepSeek 大模型接口。

3.1 初始化项目

mkdir axios-demo && cd axios-demo
bun init

package.json 长这样:

{
  "name": "axios-demo",
  "module": "index.ts",
  "type": "module",
  "dependencies": {
    "axios": "^1.17.0",
    "dotenv": "^17.4.2"
  },
  "devDependencies": {
    "@types/bun": "latest"
  }
}

安装依赖——注意,这里用 bun install 而不是 npm install,速度肉眼可见地快:

bun install

3.2 配置环境变量

创建 .env 文件,存放 API Key(永远不要把 Key 写死在代码里!):

DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com

3.3 核心代码

index.ts——用 axios 调用 LLM 的 chat/completions 接口:

import axios from 'axios';
import dotenv from 'dotenv';
dotenv.config();

async function chat() {
    try {
        const res = await axios.post(
            `${process.env.DEEPSEEK_BASE_URL}/chat/completions`,
            {
                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();

3.4 运行

bun run index.ts

不需要 ts-node,不需要 tsx,Bun 原生执行 TypeScript。你应该能看到 DeepSeek 返回的关于 Bun 的介绍文字。

3.5 HTTP 请求结构回顾

这段代码涉及的知识点,拆开来看:

┌──────────────────────────────────────────┐
│  请求行:POST /chat/completions HTTP/1.1 │
├──────────────────────────────────────────┤
│  请求头:                                │
│    Content-Type: application/json        │
│    Authorization: Bearer sk-xxx          │
├──────────────────────────────────────────┤
│  请求体:                                │
│    { model, messages }                   │
└──────────────────────────────────────────┘
  • GET 请求有长度限制,参数暴露在 URL 里,不安全
  • POST 请求把数据放在请求体(body)中,适合上传图片、发送长文本
  • API Key 放在请求头的 Authorization 字段,比拼在 URL 里安全得多
  • axios 是企业级 HTTP 框架,封装了原生 fetch,自动处理 JSON、超时、拦截器等

四、补充:async/await 的本质

代码里大量使用了 async/await,这是现代 JavaScript 处理异步的核心模式。它的底层是 Promise:

// 封装一个 sleep 函数
function sleep(t: number): Promise<void> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, t);
    });
}

async function main() {
    console.log('开始');
    await sleep(2000);  // 异步任务同步化——等 2 秒再继续
    console.log('结束');
}

main();

一句话理解 Promise:Promise 是一个「许诺」——我现在给不了你结果,但未来某个时刻一定会给你。await 就是「等这个许诺兑现了再往下走」。


五、总结

技术解决了什么问题
Bun取代 Node.js + npm,更快、更简洁、原生 TS 支持
TypeScript在编译阶段拦截类型错误,大型项目 + AI 编程的基石
axios封装 fetch,提供企业级 HTTP 请求能力
dotenv环境变量管理,避免 API Key 泄漏

Bun 被 Anthropic 收购这件事本身就说明了一切——下一代 AI 编程工具的底层,需要的是一个更快、更轻、原生支持 TypeScript 的运行时。而我们作为开发者,早一天拥抱 Bun,就早一天享受它带来的效率提升。


本文配套代码见 cw-ai/ai/backend/bun/ ,欢迎 Star ⭐ 和交流讨论!


发布于 掘金 · 2025 年