coding-rules

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

coding-rules - コーディング規約

coding-rules - 编码规范

プロジェクト共通のコーディングルール。

项目通用编码规则。

1. TypeScript

1. TypeScript

型定義

类型定义

typescript
// ✅ 明示的な型定義
interface User {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
}

// ✅ 型推論が明確な場合は省略OK
const users = await repository.findAll(); // 戻り値の型は関数から推論

// ❌ any は使わない
const data: any = response.json();

// ✅ unknown を使って安全に処理
const data: unknown = await response.json();
if (isUser(data)) {
  console.log(data.email);
}
typescript
// ✅ 显式类型定义
interface User {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
}

// ✅ 类型推论明确时可省略
const users = await repository.findAll(); // 返回值类型从函数推论

// ❌ 禁止使用any
const data: any = response.json();

// ✅ 使用unknown进行安全处理
const data: unknown = await response.json();
if (isUser(data)) {
  console.log(data.email);
}

Null/Undefined

Null/Undefined处理

typescript
// ✅ Optional chaining
const email = user?.profile?.email;

// ✅ Nullish coalescing
const name = user.name ?? 'Anonymous';

// ❌ 非推奨
const name = user.name || 'Anonymous'; // 空文字もfalsy

typescript
// ✅ 可选链操作
const email = user?.profile?.email;

// ✅ 空值合并运算符
const name = user.name ?? 'Anonymous';

// ❌ 不推荐
const name = user.name || 'Anonymous'; // 空字符串也会被视为 falsy 值

2. インポート順序

2. 导入顺序

typescript
// 1. 外部ライブラリ
import { useState } from 'react';
import { z } from 'zod';

// 2. 内部モジュール(エイリアス)
import { db } from '@/db';
import { User } from '@/types';

// 3. 相対インポート
import { helper } from './utils';
import styles from './styles.module.css';

typescript
// 1. 外部库
import { useState } from 'react';
import { z } from 'zod';

// 2. 内部模块(别名)
import { db } from '@/db';
import { User } from '@/types';

// 3. 相对路径导入
import { helper } from './utils';
import styles from './styles.module.css';

3. 命名規則

3. 命名规则

種類規則
変数・関数camelCase
getUserById
,
isActive
定数UPPER_SNAKE_CASE
MAX_RETRY_COUNT
クラス・型PascalCase
UserService
,
CreateUserInput
ファイルkebab-case
user-service.ts
ReactコンポーネントPascalCase
UserCard.tsx
環境変数UPPER_SNAKE_CASE
DATABASE_URL
类型规则示例
变量·函数camelCase
getUserById
,
isActive
常量UPPER_SNAKE_CASE
MAX_RETRY_COUNT
类·类型PascalCase
UserService
,
CreateUserInput
文件kebab-case
user-service.ts
React组件PascalCase
UserCard.tsx
环境变量UPPER_SNAKE_CASE
DATABASE_URL

Boolean命名

布尔值命名

typescript
// ✅ is/has/can/should プレフィックス
const isActive = true;
const hasPermission = user.role === 'admin';
const canEdit = isOwner || isAdmin;
const shouldRefetch = isStale && !isLoading;

typescript
// ✅ 使用is/has/can/should前缀
const isActive = true;
const hasPermission = user.role === 'admin';
const canEdit = isOwner || isAdmin;
const shouldRefetch = isStale && !isLoading;

4. 関数

4. 函数

単一責任

单一职责原则

typescript
// ❌ 複数の責任
async function processUser(userId: string) {
  const user = await db.select().from(users).where(eq(users.id, userId));
  await sendEmail(user.email);
  await updateLastLogin(userId);
  return user;
}

// ✅ 分割
async function getUser(userId: string) {
  return db.select().from(users).where(eq(users.id, userId));
}

async function notifyUser(email: string) {
  await sendEmail(email);
}

async function recordLogin(userId: string) {
  await updateLastLogin(userId);
}
typescript
// ❌ 承担多个职责
async function processUser(userId: string) {
  const user = await db.select().from(users).where(eq(users.id, userId));
  await sendEmail(user.email);
  await updateLastLogin(userId);
  return user;
}

// ✅ 拆分函数
async function getUser(userId: string) {
  return db.select().from(users).where(eq(users.id, userId));
}

async function notifyUser(email: string) {
  await sendEmail(email);
}

async function recordLogin(userId: string) {
  await updateLastLogin(userId);
}

早期リターン

提前返回

typescript
// ❌ ネスト深い
function processData(data: Data | null) {
  if (data) {
    if (data.isValid) {
      if (data.items.length > 0) {
        return data.items.map(process);
      }
    }
  }
  return [];
}

// ✅ 早期リターン
function processData(data: Data | null) {
  if (!data) return [];
  if (!data.isValid) return [];
  if (data.items.length === 0) return [];

  return data.items.map(process);
}

typescript
// ❌ 嵌套过深
function processData(data: Data | null) {
  if (data) {
    if (data.isValid) {
      if (data.items.length > 0) {
        return data.items.map(process);
      }
    }
  }
  return [];
}

// ✅ 提前返回
function processData(data: Data | null) {
  if (!data) return [];
  if (!data.isValid) return [];
  if (data.items.length === 0) return [];

  return data.items.map(process);
}

5. エラーハンドリング

5. 错误处理

typescript
// ✅ カスタムエラークラス
class ValidationError extends Error {
  constructor(
    message: string,
    public field: string
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

// ✅ 適切なエラー処理
try {
  await riskyOperation();
} catch (error) {
  if (error instanceof ValidationError) {
    return apiError(error.message, { status: 400 });
  }
  console.error('Unexpected error:', error);
  return apiError('Internal error', { status: 500 });
}

typescript
// ✅ 自定义错误类
class ValidationError extends Error {
  constructor(
    message: string,
    public field: string
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

// ✅ 合理的错误处理
try {
  await riskyOperation();
} catch (error) {
  if (error instanceof ValidationError) {
    return apiError(error.message, { status: 400 });
  }
  console.error('Unexpected error:', error);
  return apiError('Internal error', { status: 500 });
}

6. コメント

6. 注释

typescript
// ✅ WHYを説明
// Stripe APIの制限により、100件ずつバッチ処理する必要がある
const BATCH_SIZE = 100;

// ❌ WHATを説明(コードを読めばわかる)
// ユーザーを取得する
const user = await getUser(id);

// ✅ TODO/FIXME は issue番号付き
// TODO(#123): キャッシュ実装後に削除
// FIXME(#456): 競合状態の対応が必要

typescript
// ✅ 说明原因(WHY)
// 由于Stripe API限制,需要按100条为批次处理
const BATCH_SIZE = 100;

// ❌ 不说明内容(WHAT,代码本身可体现)
// 获取用户
const user = await getUser(id);

// ✅ TODO/FIXME需附带issue编号
// TODO(#123): 缓存实现后删除
// FIXME(#456): 需要处理竞争状态

7. React/Next.js

7. React/Next.js

Server vs Client Components

Server组件 vs Client组件

typescript
// Server Component (デフォルト)
// - データフェッチ
// - 機密情報アクセス
// - バンドルサイズ削減

// Client Component ('use client')
// - useState, useEffect
// - イベントハンドラ
// - ブラウザAPI

// ✅ 最小限のクライアントコンポーネント
'use client';
export function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>Like</button>;
}
typescript
// Server Component(默认)
// - 数据获取
// - 访问敏感信息
// - 减小打包体积

// Client Component ('use client')
// - 使用useState、useEffect
// - 事件处理
// - 浏览器API调用

// ✅ 最小化Client组件
'use client';
export function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>Like</button>;
}

Props

Props定义

typescript
// ✅ 型定義
interface UserCardProps {
  user: User;
  onEdit?: (id: string) => void;
  className?: string;
}

export function UserCard({ user, onEdit, className }: UserCardProps) {
  // ...
}

typescript
// ✅ 类型定义
interface UserCardProps {
  user: User;
  onEdit?: (id: string) => void;
  className?: string;
}

export function UserCard({ user, onEdit, className }: UserCardProps) {
  // ...
}

8. Git コミット

8. Git 提交

Conventional Commits

约定式提交

feat: 新機能追加
fix: バグ修正
docs: ドキュメント
refactor: リファクタリング
test: テスト
chore: その他
feat: 新增功能
fix: 修复bug
docs: 文档更新
refactor: 代码重构
test: 测试相关
chore: 其他杂项

示例

feat: add user authentication
fix: resolve login redirect loop
docs: update API documentation
refactor: extract validation logic to separate module
test: add unit tests for UserService
chore: update dependencies
feat: 添加用户认证
fix: 修复登录重定向循环问题
docs: 更新API文档
refactor: 将验证逻辑提取到独立模块
test: 为UserService添加单元测试
chore: 更新依赖