【Next.js】OSS pathpida のコントリビュータになった話

# はじめに

エンジニアとして開発をしていると、日々さまざまな OSS に助けられることが多いですよね。
便利に使わせてもらっている一方で、「自分も何か貢献できないかな？」と思ったことがある人も多いのではないでしょうか。

今回、私が普段の業務で使っている pathpida に実際に貢献する機会があったので、その過程や学びを共有したいと思います。「OSS に貢献してみたいけど、どうすればいいか分からない」という方の参考になれば嬉しいです！

## pathpidaとは

[pathpida](https://github.com/aspida/pathpida) は、TypeScript 環境で ページやファイルのパス を型安全に管理するためのライブラリです。  
`$path.ts` というファイルを自動生成し、API のパスやクエリパラメータを型付きで扱えるようになります。

### pathpida の特徴
- **エンドポイントの型安全性**
  - 文字列で API パスを管理するのではなく、型によってエラーを防げる
- **動的ルート・クエリパラメータのサポート**
  - Next.js や Nuxt.js のルーティング形式と相性が良い
- **API コールのコードをシンプルに**
  - `path` オブジェクトを通じて、直感的にエンドポイントを指定できる

例えば、以下のように `$path.ts` を生成すると、動的ルートやクエリパラメータを型安全に管理できます。
```tsx
import { pagesPath } from '../lib/$path'
console.log(pagesPath.posts._id(123).$url().path) // '/posts/123'
```

## きっかけ

私が関わっているプロジェクトでは、 pathpida を使って API のルートを型安全に管理していました。型が保証されるのでとても便利だったのですが、ある日 $path.ts を生成したときに型エラーが発生。

「え？なんで？」と思って調べてみると、 `buildSuffix` 関数のクエリパラメータの型が `Record<string, string>` になっていて、 `number` や `boolean`、配列を渡すとエラーになってしまうことが分かりました。

例えば、こんな感じです。
```tsx
(url?: { query: { id: 123, active: true, tags: ["tech", "blog"] } }) => {
...
 { path: `hoge/${buildSuffix(url)}` } // 型エラー
}
```

実際のアプリ開発では、数値や真偽値、配列をクエリパラメータに含めることは珍しくありません。これは何とかしないと！と思い、 pathpida の型定義を拡張する提案をすることにしました。

## まずは Issue を作成

いきなり PR を送るのはちょっと勇気がいるので、まずは [Issue](https://github.com/aspida/pathpida/issues/189) を作成して maintainers の方の意見を聞くことにしました。

### Issue の概要

現在、 `buildSuffix` 関数の引数として受け取るクエリパラメータの型が `Record<string, string>` となっており、 `number` や `boolean`、配列を渡すことができません。これを拡張して、より柔軟に扱えるようにしたいです。

### 提案する解決策

query の型を以下のように拡張します。
```tsx
const buildSuffix = (url?: {
  query?: Record<string, string | number | boolean | Array<string | number | boolean>>;
  hash?: string;
}) => {
  const query = url?.query;
  const hash = url?.hash;
  if (!query && !hash) return '';

  const search = (() => {
    if (!query) return '';
    const params = new URLSearchParams();
    Object.entries(query).forEach(([key, value]) => {
      if (Array.isArray(value)) {
        value.forEach((item) => params.append(key, String(item)));
      } else {
        params.set(key, String(value));
      }
    });
    return `?${params.toString()}`;
  })();

  return `${search}${hash ? `#${hash}` : ''}`;
};
```

この変更によって、以下のようなパラメータがサポートされるようになります。

- `number` や `boolean` の値を直接指定可能
- `string[]`, `number[]`, `boolean[]` などの配列形式のクエリパラメータをサポート

## PR を作成してみる

Issue で「良いですね」と了承を得たので、意を決して PR を作成しました。pathpida は2度目の PR でしたが、相変わらず緊張しました。

### PR のポイント

- `buildSuffix` の query 型を拡張し、 `string | number | boolean | Array<string | number | boolean>` を許容するように変更
- 型安全性を維持しながら、より実用的にクエリパラメータを扱えるように

## 受けたフィードバックと対応

PR を送った後、 maintainers の方からレビューが入りました。

「この機能は便利だけど、pathpida のスコープを考えると一部削除した方がいいかも」

具体的には、提案したユーティリティ型の一部が pathpida の本体機能とは少しズレていたため、削除を求められました。確かに、OSS では「どこまでを責任範囲とするか？」が重要になるので、これは納得。

修正を加えて再度レビューしてもらい、最終的に PR は無事にマージされました！

## やってみて感じたこと

今回、 pathpida に貢献することで、OSS への関わり方を学ぶことができました。

### 学び

- まずは Issue を作成して意見をもらう
  - いきなり PR を出すよりも、まずはプロジェクトの方針を確認するのが大事
- OSS ではスコープを意識することが重要
  - 良いアイデアでも、プロジェクトの責務を超えてしまうと採用されない
- フィードバックを受け入れて柔軟に対応する
  - 最初の PR が完璧じゃなくても OK！ レビューを受けてブラッシュアップすれば良い

OSS への貢献は、最初はハードルが高く感じるけど、実際にやってみるとすごく学びが多いです。今後も機会を見つけて積極的に貢献していこうと思いました！

## まとめ

- pathpida の `buildSuffix` の型定義を拡張し、 `number` や `boolean`、配列を扱えるようにする PR を作成
- Issue で合意を取りながら進めることの大切さを実感
- OSS 貢献は難しくない！小さな改善から始めるのがオススメ

「OSS に貢献してみたいけど、何からやればいいか分からない」という方は、まずは使っているライブラリの Issue を眺めることから始めてみてはいかがでしょうか？