mcpField
T
typescript-conventions

typescript-conventions

github.com/exceptionless开发2.5k48 次安装今天更新
代码仓库

关于 typescript-conventions

面向 TypeScript 项目的代码约定技能,帮助编码 Agent 遵循项目格式、命名、导入和类型安全规则。内容还规定 Promise 处理、控制流和导出方式。

主要功能

  1. 01遵循格式化与最小差异原则
  2. 02规定文件命名与导入方式
  3. 03强调类型安全并避免 any
  4. 04要求妥善处理 Promise
  5. 05统一控制流和导出约定

适用场景

  1. 01为 TypeScript 代码变更提供规范
  2. 02检查命名和导入是否一致
  3. 03指导类型定义与错误处理
  4. 04统一异步代码和导出写法

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/exceptionless/exceptionless --skill typescript-conventions

安装后在 Claude Code 中输入/typescript-conventions确认已加载。

详细介绍

TypeScript 约定

风格与格式

  • 严格遵循 .editorconfig 和 ESLint + Prettier 配置
  • 提交前运行 npm run format
  • 尽量减少差异:仅更改必要内容,保留现有格式和结构
  • 与周围代码的风格完全一致

项目前端规则

  • 所有控制流语句(if、for、while 等)都必须使用大括号。
  • 返回语句的箭头函数必须使用块体;项目代码中不要使用单表达式简写。
  • 标识符中不要使用缩写(使用 organization,而不是 org;使用 filter,而不是 filt)。
  • 避免将条件判断和返回语句写在同一行;使用多行代码块以提高可读性。

文件命名

  • 文件和目录使用 kebab-case
  • 组件文件:user-profile.svelte
  • TypeScript 文件:api-client.ts、user-service.ts
  • 测试文件:user-service.test.ts 或 user-service.spec.ts

导入

优先使用命名导入
// ✅ Good: Named imports
import { UserService, type User } from "$lib/services/user-service";
import { formatDate, formatNumber } from "$lib/utils/formatters";

// ❌ Avoid: Namespace imports (except allowed exceptions)
import * as utils from "$lib/utils";
  • 大多数模块优先使用命名导入;命名空间导入应仅限于获准的模式(例如 shadcn 组合导入)。
允许的命名空间导入
// ✅ Allowed: shadcn-svelte components
import * as Dialog from "$comp/ui/dialog";
import * as DropdownMenu from "$comp/ui/dropdown-menu";

// ✅ Allowed: Barrel exports
import * as Field from "$comp/ui/field";

类型安全

避免使用 any
// ❌ Bad
function processData(data: any) { ... }

// ✅ Good: Use interfaces/types
interface UserData {
    id: string;
    name: string;
    email: string;
}

function processData(data: UserData) { ... }

// ✅ Good: Use unknown for truly unknown data
function parseResponse(data: unknown): UserData {
    if (isUserData(data)) {
        return data;
    }
    throw new Error('Invalid data format');
}
类型守卫
function isUserData(data: unknown): data is UserData {
    return (
        typeof data === "object" &&
        data !== null &&
        "id" in data &&
        "name" in data &&
        "email" in data
    );
}

// Discriminated unions
type ApiResponse =
    | { status: "success"; data: UserData }
    | { status: "error"; error: string };

function handleResponse(response: ApiResponse) {
    if (response.status === "success") {
        // TypeScript knows response.data exists
        return response.data;
    }
    // TypeScript knows response.error exists
    throw new Error(response.error);
}

Promise 处理

始终使用 Await
// ✅ Good: Always await
const user = await fetchUser(id);
const [users, projects] = await Promise.all([fetchUsers(), fetchProjects()]);

// ❌ Bad: Fire and forget without handling
fetchUser(id); // Exception is lost!
错误处理
// ✅ Good: try/catch with proper typing
async function loadUser(id: string): Promise<User | null> {
    try {
        const response = await api.get<User>(`/users/${id}`);
        return response.data;
    } catch (error) {
        if (error instanceof ApiError) {
            console.error("API Error:", error.message);
        }
        return null;
    }
}

控制语句

所有单行控制语句都必须使用大括号:

// ✅ Good: Always use braces
if (condition) {
    doSomething();
}

for (const item of items) {
    process(item);
}

// ❌ Bad: No braces
if (condition) doSomething();

接口命名

API 相关类型遵循 HTTP 动词前缀:

// Request/Response interfaces
interface PostOrganizationRequest {
    name: string;
    billing_email: string;
}

interface GetOrganizationParams {
    id: string;
}

interface PatchUserRequest {
    name?: string;
    email?: string;
}

导出模式

// Named exports preferred
export function createUser(data: CreateUserRequest): Promise<User> { ... }
export type { User, CreateUserRequest };

// Re-export from barrel files
// src/lib/features/users/index.ts
export { createUser, updateUser, deleteUser } from './api.svelte';
export type { User, CreateUserRequest } from './models';

现代 ES6+ 特性

// Template literals
const message = `Hello, ${user.name}!`;

// Destructuring
const { id, name, email } = user;
const [first, ...rest] = items;

// Nullish coalescing
const displayName = user.nickname ?? user.name ?? "Anonymous";

// Optional chaining
const city = user?.address?.city;

// Object shorthand
const data = { id, name, createdAt: new Date() };

评论

支持 Markdown