关于 typescript-conventions
面向 TypeScript 项目的代码约定技能,帮助编码 Agent 遵循项目格式、命名、导入和类型安全规则。内容还规定 Promise 处理、控制流和导出方式。
主要功能
- 01遵循格式化与最小差异原则
- 02规定文件命名与导入方式
- 03强调类型安全并避免 any
- 04要求妥善处理 Promise
- 05统一控制流和导出约定
适用场景
- 01为 TypeScript 代码变更提供规范
- 02检查命名和导入是否一致
- 03指导类型定义与错误处理
- 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