背景
PR #260 の processMdFilesParallel (file-private helper) / PR #258 の getActiveTab (file-private helper) に続き、PR #271 で src/stores/settings.ts に makeSetter<K extends keyof SettingsValues> closure factory を導入した。
同 PR の /simplify 4 reviewer 並列 review で Reuse + Altitude の 2 reviewer が同一 mechanism を指摘:
src/stores/git-sync.ts:82-114 に 同 shape の 7 setter (setGitSyncEnabled / setAutoCommitInterval / setAutoPullInterval / setAutoPushInterval / setPullBeforePush / setSyncMethod / setAutoPullOnStartup) が既に存在 → 2 箇所目確定
- HANDOFF 49 ★「次 PR で 2 箇所目が発生したら helper 化」基準を満たす
- 現状
makeSetter は SettingsValues に固有 (create() 内 closure) → 共通化余地
PR #271 で見送った理由
- user が明示採択した scope が「
src/stores/settings.ts 1 file 内 setter 集約」で、git-sync.ts への横展開は本 scope 外
- HANDOFF 52 ★「skip 判定は次 PR での解消策を明示」pattern に従い、shared helper 化を 本 issue で切り出し
Option A: src/lib/store-helpers.ts に makePersistedSetter<TValues, K> を hoist (推奨)
// src/lib/store-helpers.ts (新規)
export function makePersistedSetter<TValues, K extends keyof TValues>(
set: (partial: Partial<TValues>) => void,
key: K,
save: (value: TValues[K]) => Promise<void>,
normalize?: (value: TValues[K]) => TValues[K],
) {
return (value: TValues[K]) => {
const normalized = normalize ? normalize(value) : value;
void save(normalized);
set({ [key]: normalized } as Partial<TValues>);
};
}
呼び出し側:
// src/stores/settings.ts
setShowLineNumbers: makePersistedSetter(set, "showLineNumbers", saveShowLineNumbers),
// ... 11 setter ...
// src/stores/git-sync.ts
setGitSyncEnabled: makePersistedSetter(set, "gitSyncEnabled", saveGitSyncEnabled),
// ... 7 setter ...
setCommitMessage: makePersistedSetter(set, "commitMessage", saveCommitMessage, (v) => v.trim() || DEFAULTS.commitMessage),
Option B: file-private closure を各 store で維持 (現状)
- settings.ts と git-sync.ts に別々の
makeSetter closure を配置
- 重複するが scope 完全隔離
Option A 採用根拠 (PR #271 skip 判定の解消)
- HANDOFF 49 ★「次 PR で 2 箇所目が発生したら helper 化」基準成立 — settings.ts で 1 箇所目、git-sync.ts に 2 箇所目 existing → 2 箇所目確定時点で helper 化するのが judgment rule
- 削減効果: git-sync.ts で 7 setter ×
2 行 = **-14 行**、settings.ts で +2 行 (import + factory 位置変更) 差し引き net -12 行程度
- generic factory で型安全 —
TValues + K extends keyof TValues により settings/git-sync 両方の key/value 対応を静的保証
setCommitMessage の normalize 統合 — Altitude reviewer が指摘: shared helper に normalize? optional transform を持たせれば、setCommitMessage の normalize → save → set shape も含めて全 setter を統一表現可能。将来 3 番目のストアで normalize 需要が出ても同 API で対応可能
as Partial<SettingsState> cast を helper 内部に隔離 — TS computed-key widening の cast が呼び出し側に露出せず、helper 内部の 1 箇所で完結
対象ファイル
src/lib/store-helpers.ts (新規、~15 行)
src/stores/settings.ts (現 83 行 → 現状 closure 削除 + helper import + 呼び出し形変更、diff は ±3 行程度)
src/stores/git-sync.ts (setter 7 個を helper 呼び出しに置換、setCommitMessage は normalize callback で統合、~-14 行)
- test 影響:
src/stores/settings.test.ts (14 pass) と src/stores/git-sync.test.ts が外部 API 不変なので pass 継続想定
参考
背景
PR #260 の
processMdFilesParallel(file-private helper) / PR #258 のgetActiveTab(file-private helper) に続き、PR #271 でsrc/stores/settings.tsにmakeSetter<K extends keyof SettingsValues>closure factory を導入した。同 PR の
/simplify4 reviewer 並列 review で Reuse + Altitude の 2 reviewer が同一 mechanism を指摘:src/stores/git-sync.ts:82-114に 同 shape の 7 setter (setGitSyncEnabled/setAutoCommitInterval/setAutoPullInterval/setAutoPushInterval/setPullBeforePush/setSyncMethod/setAutoPullOnStartup) が既に存在 → 2 箇所目確定makeSetterはSettingsValuesに固有 (create() 内 closure) → 共通化余地PR #271 で見送った理由
src/stores/settings.ts1 file 内 setter 集約」で、git-sync.tsへの横展開は本 scope 外Option A:
src/lib/store-helpers.tsにmakePersistedSetter<TValues, K>を hoist (推奨)呼び出し側:
Option B: file-private closure を各 store で維持 (現状)
makeSetterclosure を配置Option A 採用根拠 (PR #271 skip 判定の解消)
2 行 = **-14 行**、settings.ts で +2 行 (import + factory 位置変更) 差し引き net -12 行程度TValues+K extends keyof TValuesにより settings/git-sync 両方の key/value 対応を静的保証setCommitMessageの normalize 統合 — Altitude reviewer が指摘: shared helper にnormalize?optional transform を持たせれば、setCommitMessageのnormalize → save → setshape も含めて全 setter を統一表現可能。将来 3 番目のストアで normalize 需要が出ても同 API で対応可能as Partial<SettingsState>cast を helper 内部に隔離 — TS computed-key widening の cast が呼び出し側に露出せず、helper 内部の 1 箇所で完結対象ファイル
src/lib/store-helpers.ts(新規、~15 行)src/stores/settings.ts(現 83 行 → 現状 closure 削除 + helper import + 呼び出し形変更、diff は ±3 行程度)src/stores/git-sync.ts(setter 7 個を helper 呼び出しに置換、setCommitMessageは normalize callback で統合、~-14 行)src/stores/settings.test.ts(14 pass) とsrc/stores/git-sync.test.tsが外部 API 不変なので pass 継続想定参考
/simplify指摘を本 PR で skip → follow-up issue に skip 判定の解消策を明示)