Deno 原生支持 TypeScript,这是其最吸引人的特性之一。与 Node.js 需要配置 TypeScript 编译器不同,Deno 可以直接运行 TypeScript 文件,无需任何额外的转译步骤。
TypeScript 支持概述
Deno 内置了 TypeScript 编译器,使用 V8 引擎的 TypeScript 支持和 swc 编译器来提供快速的类型检查和转译。
直接运行 TypeScript
1. 基本用法
typescript// app.ts interface User { id: number; name: string; email: string; } function createUser(user: User): User { console.log(`Creating user: ${user.name}`); return user; } const newUser: User = { id: 1, name: "John Doe", email: "john@example.com" }; createUser(newUser);
运行:
bashdeno run app.ts
2. 类型检查
Deno 会在运行时进行类型检查:
bash# 运行时进行类型检查 deno run app.ts # 仅类型检查(不执行) deno check app.ts # 类型检查所有文件 deno check **/*.ts
类型定义
1. 使用 Deno 内置类型
Deno 提供了丰富的内置类型定义:
typescript// 文件系统操作 const content: string = await Deno.readTextFile("./data.txt"); // HTTP 服务器 import { serve } from "https://deno.land/std@0.208.0/http/server.ts"; const handler = async (req: Request): Promise<Response> => { return new Response("Hello World"); };
2. 第三方库类型
从 URL 导入的模块通常包含类型定义:
typescriptimport { Application, Router } from "https://deno.land/x/oak@v12.6.1/mod.ts"; const app = new Application(); const router = new Router();
3. 自定义类型定义
如果模块没有类型定义,可以创建自定义类型:
typescript// types.d.ts declare module "https://example.com/module.js" { export function doSomething(): void; export const value: number; }
配置选项
1. tsconfig.json
Deno 支持使用 tsconfig.json 进行配置:
json{ "compilerOptions": { "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
2. 命令行选项
bash# 禁用类型检查(不推荐) deno run --no-check app.ts # 使用特定的 tsconfig deno run --config=tsconfig.json app.ts # 启用严格模式 deno run app.ts # 默认启用严格模式
类型检查策略
1. 本地类型检查
bash# 检查本地文件 deno check app.ts # 检查整个项目 deno check src/**/*.ts
2. 远程类型检查
Deno 会缓存远程模块的类型定义:
bash# 重新下载并检查远程类型 deno check --remote app.ts # 清除类型缓存 deno cache --reload app.ts
实际应用示例
1. 类型安全的 API 服务器
typescript// api-server.ts interface User { id: number; name: string; email: string; } interface CreateUserRequest { name: string; email: string; } const users: Map<number, User> = new Map(); function createUser(request: CreateUserRequest): User { const id = users.size + 1; const user: User = { id, ...request }; users.set(id, user); return user; } import { serve } from "https://deno.land/std@0.208.0/http/server.ts"; const handler = async (req: Request): Promise<Response> => { const url = new URL(req.url); if (req.method === "POST" && url.pathname === "/users") { try { const body: CreateUserRequest = await req.json(); const user = createUser(body); return new Response(JSON.stringify(user), { headers: { "Content-Type": "application/json" } }); } catch (error) { return new Response("Invalid request", { status: 400 }); } } return new Response("Not Found", { status: 404 }); }; await serve(handler, { port: 8000 });
2. 类型安全的数据库操作
typescript// database.ts interface DatabaseRecord { id: string; createdAt: Date; updatedAt: Date; } interface Post extends DatabaseRecord { title: string; content: string; authorId: string; } class Database<T extends DatabaseRecord> { private records: Map<string, T> = new Map(); async create(record: Omit<T, keyof DatabaseRecord>): Promise<T> { const id = crypto.randomUUID(); const now = new Date(); const newRecord: T = { id, createdAt: now, updatedAt: now, ...record } as T; this.records.set(id, newRecord); return newRecord; } async findById(id: string): Promise<T | undefined> { return this.records.get(id); } } const postDB = new Database<Post(); const newPost = await postDB.create({ title: "Hello Deno", content: "TypeScript support is amazing!", authorId: "user-1" });
3. 类型安全的工具函数
typescript// utils.ts type AsyncFunction<T = any> = (...args: any[]) => Promise<T>; async function retry<T>( fn: AsyncFunction<T>, maxAttempts: number = 3, delay: number = 1000 ): Promise<T> { let lastError: Error | undefined; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error as Error; if (attempt < maxAttempts) { await new Promise(resolve => setTimeout(resolve, delay)); } } } throw lastError; } async function fetchWithTimeout( url: string, timeout: number = 5000 ): Promise<Response> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { signal: controller.signal }); clearTimeout(timeoutId); return response; } catch (error) { clearTimeout(timeoutId); throw error; } }
类型检查性能优化
1. 增量类型检查
Deno 会缓存类型检查结果:
bash# 首次运行会进行完整类型检查 deno run app.ts # 后续运行会使用缓存 deno run app.ts
2. 选择性类型检查
bash# 只检查修改的文件 deno check app.ts # 排除某些文件 deno check --exclude=**/*.test.ts src/**/*.ts
与 Node.js 的对比
| 特性 | Deno | Node.js |
|---|---|---|
| TypeScript 支持 | 原生支持 | 需要配置 tsc |
| 运行方式 | 直接运行 .ts 文件 | 需要先编译为 .js |
| 类型检查 | 运行时检查 | 编译时检查 |
| 配置复杂度 | 零配置 | 需要 tsconfig.json |
| 性能 | 使用 swc 快速编译 | 使用 tsc 较慢 |
| 类型定义 | 自动加载 | 需要 @types 包 |
最佳实践
- 始终使用类型:充分利用 TypeScript 的类型系统
- 启用严格模式:使用
strict: true获得更好的类型安全 - 使用接口定义数据结构:明确 API 和数据模型的类型
- 避免 any 类型:使用 unknown 或具体类型替代
- 定期运行类型检查:使用
deno check确保代码质量 - 利用泛型:编写可复用的类型安全代码
Deno 的 TypeScript 支持使得开发者能够享受类型安全的好处,而无需复杂的配置和构建流程,大大提高了开发效率和代码质量。