• #prettier
  • #vscode
  • #claude-code
  • #formatter
  • #dx
開発tax-assistantメモ

問題: VSCode保存時にClaude Codeのコードが勝手にフォーマットされる

tax-assistantプロジェクトの開発中、Claude Codeが書いたコードをVSCodeで保存するたびに、フォーマッターが走ってコードが書き換わる問題が発生した。

VSCodeの formatOnSave が有効で、デフォルトのPrettier設定が適用されていたことが原因。

具体的に起きたこと

1. インデントが2スペースから4スペースに変わる

Claude Codeは2スペースインデントでコードを生成するが、保存するとVSCodeのデフォルト設定で4スペースに変換される。

// Claude Codeが書いたコード(2スペース)
const calculate = (items: Item[]) => {
  return items
    .filter(item => item.active)
    .reduce((sum, item) => sum + item.price, 0);
};

// 保存後(4スペースに変換される)
const calculate = (items: Item[]) => {
    return items
        .filter(item => item.active)
        .reduce((sum, item) => sum + item.price, 0);
};

2. 1行で書いたコードが80文字で折り返される

Prettierのデフォルト printWidth は80文字。Claude Codeが1行で書いた読みやすいコードが、保存するだけで複数行に分割される。

// Claude Codeが書いたコード(1行で読みやすい)
const result = items.filter(item => item.category === 'active').map(item => item.name);

// 保存後(80文字で折り返される)
const result = items
  .filter(
    (item) =>
      item.category === 'active'
  )
  .map((item) => item.name);

特にメソッドチェーンや条件式が無駄に分割されて、かえって読みにくくなるケースが多かった。

3. TypeScript型セパレータが , から ; に変わる

これがPrettier固有の仕様で、設定で変更できない。

// Claude Codeが書いたコード(カンマ区切り)
type LoanParams = {
  principal: number,
  annualRate: number,
  years: number,
}

// 保存後(セミコロン区切りに変換される)
type LoanParams = {
  principal: number;
  annualRate: number;
  years: number;
};

Prettierの公式見解として、TypeScriptの型定義におけるセパレータは ; に統一する方針で、この挙動を設定で変えることはできない。

Prettier enforces semicolons in TypeScript interfaces and type literals. This is not configurable.

git diffが確認しづらい

これらの自動フォーマットの結果、git diff がフォーマット変更のノイズだらけになる。

  const calculate = (items: Item[]) => {
-  return items
-    .filter(item => item.active)
-    .reduce((sum, item) => sum + item.price, 0);
+    return items
+        .filter((item) => item.active)
+        .reduce((sum, item) => sum + item.price, 0);
  };

ロジック変更とフォーマット変更が混在して、コードレビューで実際に何が変わったのか判別しにくい。Claude Codeが意図的に書いた構造なのか、フォーマッターが勝手に変えたのかがわからなくなる。

解決: .prettierrc の作成

プロジェクトルートに .prettierrc を作成し、Claude Codeの出力スタイルに合わせた設定にした。

設定ファイル

// frontend/.prettierrc
{
  "tabWidth": 2,
  "useTabs": false,
  "printWidth": 120,
  "singleQuote": true,
  "trailingComma": "all",
  "semi": true,
  "bracketSpacing": true
}

各設定の意図

設定理由
tabWidth2Claude Codeの出力に合わせて2スペース
useTabsfalseスペースインデント
printWidth12080文字だと過剰な折り返しが発生するため120に緩和
singleQuotetrueシングルクォート統一
trailingComma"all"trailing commaあり(diffが見やすい)
semitrueセミコロンあり
bracketSpacingtrue{ value } のようにスペースを入れる

printWidthを120にした理由

80文字はターミナルの横幅を想定した伝統的な値だが、現代の開発環境では狭すぎる。

  • モニタの解像度が上がり、エディタの横幅に余裕がある
  • メソッドチェーンや型定義が1行に収まりやすくなる
  • Claude Codeが生成するコードは1行の情報密度が適切で、120文字あれば不要な折り返しが減る

ただし120を超える行は折り返されるので、極端に長い行は書けない。ちょうどいいバランス。

TypeScript型セパレータの ; 問題について

前述の通り、Prettierでは型定義のセパレータを , にする設定がない。これはPrettierの設計思想(opinionated formatter)による制約。

対応方針として、これは受け入れることにした。理由は以下の通り。

  • 型定義のセパレータが , でも ; でもTypeScriptの動作に影響はない
  • プロジェクト内で統一されていれば読みやすさは変わらない
  • Prettierがセミコロンに揃えてくれるなら、Claude Codeが , で書いても保存時に統一される
  • diffのノイズにはなるが、他のフォーマット変更(インデント、折り返し)に比べれば影響は小さい

git checkout で特定ファイルだけ戻す際の注意点

フォーマット変更だけを戻したい場合、git checkout で特定ファイルを元に戻す方法がある。

# 特定ファイルの変更を元に戻す
git checkout -- path/to/file.ts

ただし、ここに落とし穴がある。

ロジック変更とフォーマット変更が混在するファイル

Claude Codeがロジックを変更したファイルに対して、保存時にフォーマッターも走った場合、そのファイルには「ロジック変更」と「フォーマット変更」の両方が含まれる。

# ❌ 危険: ロジック変更ごと消える
git checkout -- src/components/LoanCalculator.vue

このコマンドを実行すると、フォーマット変更だけでなくロジック変更も一緒に消える。Claude Codeが実装したビジネスロジックが丸ごと失われる。

安全な手順

  1. まず git diff でファイルの変更内容を確認する
  2. フォーマット変更のみのファイルは git checkout で戻してOK
  3. ロジック変更を含むファイルは git checkout しない
  4. ロジック変更を含むファイルのフォーマットノイズは、.prettierrc 導入後に npx prettier --write で統一する
# 手順例

# 1. 変更ファイル一覧を確認
git diff --name-only

# 2. 各ファイルの変更内容を確認
git diff path/to/file.ts

# 3. フォーマット変更のみのファイルを戻す
git checkout -- src/utils/helpers.ts
git checkout -- src/types/index.ts

# 4. ロジック変更を含むファイルはPrettierで再フォーマット
npx prettier --write src/components/LoanCalculator.vue

もっと安全な方法: .prettierrc を先に入れる

ベストプラクティスとして、.prettierrc をプロジェクト初期に導入しておくのが一番良い。

# .prettierrcを作成してからPrettierで全ファイルをフォーマット
npx prettier --write "src/**/*.{ts,tsx,vue}"

# この時点でコミット(フォーマット統一コミット)
git add -A
git commit -m "style: Prettierフォーマット統一"

# 以後、Claude Codeの出力と保存時フォーマットが一致するので
# diffにフォーマットノイズが混じらない

まとめ

問題原因解決
インデントが変わるVSCodeデフォルトが4スペース.prettierrctabWidth: 2
80文字で折り返されるPrettierデフォルトの printWidthprintWidth: 120 に変更
型セパレータが変わるPrettierの仕様(設定変更不可)受け入れる
git diffが見にくいフォーマット変更のノイズ.prettierrc で統一

Claude Codeと人間が同じプロジェクトで作業する場合、フォーマッターの設定を明示的に揃えておくことが大事。設定ファイルがない状態だと、それぞれのデフォルト設定が衝突してdiffが荒れる。.prettierrc を1つ置くだけで解決できる。