diff --git a/packages/tsconfig/README.md b/packages/tsconfig/README.md new file mode 100644 index 0000000..34d57b1 --- /dev/null +++ b/packages/tsconfig/README.md @@ -0,0 +1,64 @@ +# @plainbrew/tsconfig + +plainbrew プロジェクト向けの strict な TypeScript 設定。 + +## 使い方 + +> **TypeScript >= 5.8 が必要です** (`erasableSyntaxOnly` は TS 5.8+、`noUncheckedSideEffectImports` は TS 5.6+) + +```jsonc +// ベース +{ "extends": "@plainbrew/tsconfig" } + +// React +{ "extends": "@plainbrew/tsconfig/react" } +``` + +## 設計判断 + +`@tsconfig/strictest`, `@sindresorhus/tsconfig`, `@total-typescript/tsconfig` 等の大規模 OSS を参考に設計。 + +### Strict 系 + +| オプション | 採用理由 | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| [`strict`](https://www.typescriptlang.org/tsconfig/#strict) | `strictNullChecks`, `noImplicitAny` 等を一括有効化 | +| [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes) | `undefined` の明示的な使用を強制。`@tsconfig/strictest` と同方針 | +| [`noFallthroughCasesInSwitch`](https://www.typescriptlang.org/tsconfig/#noFallthroughCasesInSwitch) | switch 文の break 忘れを防止 | +| [`noImplicitOverride`](https://www.typescriptlang.org/tsconfig/#noImplicitOverride) | `override` キーワードの明示を強制し、継承元の変更検知を容易に | +| [`noImplicitReturns`](https://www.typescriptlang.org/tsconfig/#noImplicitReturns) | 全コードパスでの return を強制 | +| [`noPropertyAccessFromIndexSignature`](https://www.typescriptlang.org/tsconfig/#noPropertyAccessFromIndexSignature) | index signature へのドットアクセスを禁止し、bracket notation を強制 | +| [`noUncheckedIndexedAccess`](https://www.typescriptlang.org/tsconfig/#noUncheckedIndexedAccess) | 配列・オブジェクトのインデックスアクセスに `undefined` を含める | +| [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports) | `import "./styles.css"` 等の副作用 import の存在チェック (TS 5.6+)。`@sindresorhus/tsconfig` が採用 | +| [`noUnusedLocals`](https://www.typescriptlang.org/tsconfig/#noUnusedLocals) / [`noUnusedParameters`](https://www.typescriptlang.org/tsconfig/#noUnusedParameters) | 未使用変数・引数を検出 | +| [`allowUnusedLabels`](https://www.typescriptlang.org/tsconfig/#allowUnusedLabels) / [`allowUnreachableCode`](https://www.typescriptlang.org/tsconfig/#allowUnreachableCode) | `false` に設定。到達不能コードや未使用ラベルをエラーに | +| [`erasableSyntaxOnly`](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly) | `enum`, `namespace` 等の型消去不可能な構文を禁止 (TS 5.8+)。Node.js の `--experimental-strip-types` と互換。`@sindresorhus/tsconfig` が採用 | + +### Module 系 + +| オプション | 採用理由 | +| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| [`module`](https://www.typescriptlang.org/tsconfig/#module): `"preserve"` | import/export をそのまま保持しバンドラーに委ねる (TS 5.4+) | +| [`moduleResolution`](https://www.typescriptlang.org/tsconfig/#moduleResolution): `"bundler"` | Vite, webpack, Next.js 等のバンドラー環境に最適化 | +| [`moduleDetection`](https://www.typescriptlang.org/tsconfig/#moduleDetection): `"force"` | 全ファイルをモジュールとして扱いグローバルスコープ汚染を防止。`@total-typescript/tsconfig`, `@sindresorhus/tsconfig` が採用 | +| [`isolatedModules`](https://www.typescriptlang.org/tsconfig/#isolatedModules) | ファイル単位のトランスパイルを保証。esbuild, SWC 等との互換性確保 | +| [`esModuleInterop`](https://www.typescriptlang.org/tsconfig/#esModuleInterop) | CJS モジュールの default import を安全に扱う。`verbatimModuleSyntax` は CJS 環境で問題があるため不採用(ESLint ルールで代替) | +| [`resolveJsonModule`](https://www.typescriptlang.org/tsconfig/#resolveJsonModule) | JSON ファイルの型安全な import を許可 | +| [`skipLibCheck`](https://www.typescriptlang.org/tsconfig/#skipLibCheck) | `.d.ts` のチェックをスキップしビルド高速化。ほぼ全ての主要パッケージが採用 | + +### 意図的に含めないオプション + +| オプション | 不採用理由 | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| [`target`](https://www.typescriptlang.org/tsconfig/#target) / [`lib`](https://www.typescriptlang.org/tsconfig/#lib) | 実行環境に依存するため拡張先に委ねる | +| [`declaration`](https://www.typescriptlang.org/tsconfig/#declaration) / [`declarationMap`](https://www.typescriptlang.org/tsconfig/#declarationMap) / [`sourceMap`](https://www.typescriptlang.org/tsconfig/#sourceMap) | output 系は strictness と無関係。app と library で要件が異なる | +| [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) | CJS 出力環境で `import` を `require()` に変換不可。ESLint (`@typescript-eslint/consistent-type-imports`) で代替可能 | +| [`forceConsistentCasingInFileNames`](https://www.typescriptlang.org/tsconfig/#forceConsistentCasingInFileNames) | TS 5.0 以降デフォルト `true` | +| [`noEmit`](https://www.typescriptlang.org/tsconfig/#noEmit) | バンドラー/フレームワーク設定に依存 | + +### React 設定 (`react.json`) + +ベースを継承し、React 固有のオプションのみ追加: + +- [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx): `"react-jsx"` — React 17+ の JSX Transform を使用 +- [`lib`](https://www.typescriptlang.org/tsconfig/#lib): `["dom", "dom.iterable", "esnext"]` — ブラウザ API の型定義 diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json new file mode 100644 index 0000000..de0d557 --- /dev/null +++ b/packages/tsconfig/package.json @@ -0,0 +1,24 @@ +{ + "name": "@plainbrew/tsconfig", + "version": "0.1.0", + "description": "Strict TypeScript configuration for plainbrew projects", + "keywords": [ + "react", + "strict", + "tsconfig", + "typescript" + ], + "license": "MIT", + "files": [ + "tsconfig.json", + "react.json" + ], + "type": "module", + "exports": { + ".": "./tsconfig.json", + "./react": "./react.json" + }, + "peerDependencies": { + "typescript": ">=5.8.0" + } +} diff --git a/packages/tsconfig/react.json b/packages/tsconfig/react.json new file mode 100644 index 0000000..1d9cefb --- /dev/null +++ b/packages/tsconfig/react.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "lib": ["dom", "dom.iterable", "esnext"] + } +} diff --git a/packages/tsconfig/tsconfig.json b/packages/tsconfig/tsconfig.json new file mode 100644 index 0000000..cb46e96 --- /dev/null +++ b/packages/tsconfig/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "strict": true, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUncheckedSideEffectImports": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "erasableSyntaxOnly": true, + "isolatedModules": true, + "esModuleInterop": true, + "skipLibCheck": true, + "moduleDetection": "force", + "moduleResolution": "bundler", + "module": "preserve", + "resolveJsonModule": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb60993..262d430 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,12 @@ importers: specifier: ^0.27.0 version: 0.27.0 + packages/tsconfig: + dependencies: + typescript: + specifier: '>=5.8.0' + version: 5.9.3 + packages: '@oxfmt/darwin-arm64@0.27.0': @@ -208,6 +214,11 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -382,6 +393,8 @@ snapshots: dependencies: is-number: 7.0.0 + typescript@5.9.3: {} + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..dee51e9 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - "packages/*"