Skip to content

Bun TypeScript 支持

Bun 原生支持 TypeScript,无需任何配置即可直接运行 .ts.tsx 文件。本章介绍 Bun 的 TypeScript 特性和最佳实践。

开箱即用

直接运行 TypeScript

typescript
// app.ts
interface User {
  id: number;
  name: string;
  email: string;
}

function greet(user: User): string {
  return `Hello, ${user.name}!`;
}

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com"
};

console.log(greet(user));

运行:

bash
bun app.ts
# 输出: Hello, 张三!

无需

  • 安装 typescript
  • 配置 ts-node
  • 预编译步骤

TypeScript 配置

自动生成 tsconfig.json

bash
# 初始化项目时自动创建
bun init

# 或手动创建
bun tsc --init

推荐配置

json
{
  "compilerOptions": {
    // 目标和模块
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    
    // 严格模式
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    
    // 路径配置
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    
    // JSX 支持
    "jsx": "react-jsx",
    
    // 其他选项
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    
    // 输出目录
    "outDir": "./dist",
    "rootDir": "./src",
    
    // Bun 类型
    "types": ["bun-types"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Bun 类型定义

bash
# 安装 Bun 类型定义
bun add -d @types/bun

获得完整的 Bun API 类型提示:

typescript
// 现在有完整的类型支持
const file = Bun.file("./data.txt");
const content: string = await file.text();

const server = Bun.serve({
  port: 3000,
  fetch(request: Request): Response {
    return new Response("Hello!");
  }
});

类型检查

运行类型检查

Bun 运行时不进行类型检查(为了速度),需要单独运行:

bash
# 使用 TypeScript 编译器检查
bun tsc --noEmit

# 或在 package.json 中配置
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "dev": "bun --watch src/index.ts",
    "build": "bun run typecheck && bun build src/index.ts --outdir dist"
  }
}

类型错误示例

typescript
// error.ts
function add(a: number, b: number): number {
  return a + b;
}

// TypeScript 会报错,但 Bun 仍会运行
add("1", 2);  // 类型错误
bash
# Bun 会运行(忽略类型错误)
bun error.ts

# TypeScript 检查会报错
bun tsc --noEmit
# error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

TSX / JSX 支持

React 组件

tsx
// App.tsx
import React from "react";

interface Props {
  name: string;
  age?: number;
}

const Greeting: React.FC<Props> = ({ name, age }) => {
  return (
    <div>
      <h1>你好, {name}!</h1>
      {age && <p>年龄: {age}</p>}
    </div>
  );
};

export default Greeting;

服务端渲染

tsx
// server.tsx
import { renderToString } from "react-dom/server";
import App from "./App";

const server = Bun.serve({
  port: 3000,
  fetch(request) {
    const html = renderToString(<App name="Bun" />);
    return new Response(`
      <!DOCTYPE html>
      <html>
        <head><title>Bun React SSR</title></head>
        <body>
          <div id="root">${html}</div>
        </body>
      </html>
    `, {
      headers: { "Content-Type": "text/html" }
    });
  }
});

JSX 配置

json
// tsconfig.json
{
  "compilerOptions": {
    // React 17+ 新 JSX 转换
    "jsx": "react-jsx",
    "jsxImportSource": "react",
    
    // 或使用经典转换
    // "jsx": "react",
    
    // 使用 Preact
    // "jsx": "react-jsx",
    // "jsxImportSource": "preact"
  }
}

类型导入

导入类型

typescript
// types.ts
export interface User {
  id: number;
  name: string;
}

export type Status = "active" | "inactive" | "pending";

// main.ts
// 类型导入(不会包含在运行时代码中)
import type { User, Status } from "./types";

// 或混合导入
import { type User, type Status } from "./types";

function processUser(user: User, status: Status) {
  console.log(`${user.name}: ${status}`);
}

内联类型导入

typescript
// 确保类型只在类型上下文使用
import { type User } from "./types";

泛型

泛型函数

typescript
function identity<T>(value: T): T {
  return value;
}

const num = identity<number>(42);
const str = identity("hello");  // 类型推断

// 泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: "张三", age: 25 };
const name = getProperty(user, "name");  // string

泛型类

typescript
class Container<T> {
  private value: T;
  
  constructor(value: T) {
    this.value = value;
  }
  
  getValue(): T {
    return this.value;
  }
  
  setValue(value: T): void {
    this.value = value;
  }
}

const numberContainer = new Container<number>(42);
const stringContainer = new Container("hello");

泛型接口

typescript
interface Repository<T> {
  findById(id: number): Promise<T | null>;
  findAll(): Promise<T[]>;
  save(entity: T): Promise<T>;
  delete(id: number): Promise<boolean>;
}

interface User {
  id: number;
  name: string;
}

class UserRepository implements Repository<User> {
  private users: User[] = [];
  
  async findById(id: number): Promise<User | null> {
    return this.users.find(u => u.id === id) || null;
  }
  
  async findAll(): Promise<User[]> {
    return this.users;
  }
  
  async save(user: User): Promise<User> {
    this.users.push(user);
    return user;
  }
  
  async delete(id: number): Promise<boolean> {
    const index = this.users.findIndex(u => u.id === id);
    if (index !== -1) {
      this.users.splice(index, 1);
      return true;
    }
    return false;
  }
}

装饰器

启用装饰器

json
// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

类装饰器

typescript
function Logger(constructor: Function) {
  console.log(`类 ${constructor.name} 被创建`);
}

@Logger
class MyService {
  constructor() {
    console.log("MyService 实例化");
  }
}

// 输出:
// 类 MyService 被创建
// MyService 实例化

方法装饰器

typescript
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  
  descriptor.value = function(...args: any[]) {
    console.log(`调用 ${propertyKey},参数:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`${propertyKey} 返回:`, result);
    return result;
  };
  
  return descriptor;
}

class Calculator {
  @Log
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3);
// 输出:
// 调用 add,参数: [2, 3]
// add 返回: 5

工具类型

常用工具类型

typescript
interface User {
  id: number;
  name: string;
  email: string;
  age?: number;
}

// Partial - 所有属性可选
type PartialUser = Partial<User>;

// Required - 所有属性必需
type RequiredUser = Required<User>;

// Readonly - 所有属性只读
type ReadonlyUser = Readonly<User>;

// Pick - 选择部分属性
type UserBasic = Pick<User, "id" | "name">;

// Omit - 排除部分属性
type UserWithoutEmail = Omit<User, "email">;

// Record - 创建对象类型
type UserMap = Record<number, User>;

// Extract / Exclude - 类型过滤
type Status = "active" | "inactive" | "pending";
type ActiveStatus = Extract<Status, "active" | "pending">;
type InactiveStatus = Exclude<Status, "active">;

自定义工具类型

typescript
// 深度只读
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object
    ? DeepReadonly<T[K]>
    : T[K];
};

// 非空属性
type NonNullableFields<T> = {
  [K in keyof T]: NonNullable<T[K]>;
};

// 函数参数类型
type FunctionParams<T> = T extends (...args: infer P) => any ? P : never;

类型守卫

类型守卫函数

typescript
interface Dog {
  kind: "dog";
  bark(): void;
}

interface Cat {
  kind: "cat";
  meow(): void;
}

type Animal = Dog | Cat;

// 类型守卫
function isDog(animal: Animal): animal is Dog {
  return animal.kind === "dog";
}

function handleAnimal(animal: Animal) {
  if (isDog(animal)) {
    animal.bark();  // TypeScript 知道这是 Dog
  } else {
    animal.meow();  // TypeScript 知道这是 Cat
  }
}

in 运算符

typescript
interface Admin {
  role: "admin";
  permissions: string[];
}

interface User {
  role: "user";
  profile: object;
}

function handlePerson(person: Admin | User) {
  if ("permissions" in person) {
    console.log(person.permissions);  // Admin
  } else {
    console.log(person.profile);  // User
  }
}

构建 TypeScript 项目

编译输出

bash
# 使用 Bun 打包(转译为 JavaScript)
bun build src/index.ts --outdir dist

# 生成类型定义
bun tsc --emitDeclarationOnly

完整构建流程

json
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "build": "bun run typecheck && bun build src/index.ts --outdir dist --target node",
    "build:types": "tsc --emitDeclarationOnly --outDir dist",
    "prepublish": "bun run build && bun run build:types"
  }
}

小结

本章介绍了:

  • ✅ Bun 原生 TypeScript 支持
  • ✅ tsconfig.json 配置
  • ✅ TSX/JSX 支持
  • ✅ 类型检查和类型导入
  • ✅ 泛型和装饰器
  • ✅ 工具类型和类型守卫
  • ✅ 构建 TypeScript 项目

下一步

继续阅读 环境变量 了解 Bun 的环境配置管理。

本站内容仅供学习和研究使用。