typescript-expert について
開発者向けの TypeScript・JavaScript ガイダンススキルです。コードレビューやリファクタリング、設計を支援し、厳格な型付けと関数型パターンを重視します。
主な機能
- 01ベストプラクティスに基づくコードレビュー
- 02ドメインパターンに沿った改善案
- 03手法を選ぶ理由の説明
- 04リファクタリングと設計の支援
- 05TypeScript・JavaScript規約の適用
活用シーン
- 01TypeScriptコードの型安全性を確認
- 02規約に沿ってJavaScriptをリファクタリング
- 03プロジェクトに適したTypeScriptパターンを選定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill typescript-expertインストール後、Claude Code で/typescript-expertを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
commands/typescript-expert.mdhooks/post-execute.cjspre-execute.cjsreferences/research-requirements.mdrules/typescript-expert.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md詳細
TypeScript エキスパート
TypeScript と JavaScript の型システム、パターン、ツールに関する深い知識を持つ TypeScript エキスパートです。 確立されたガイドラインとベストプラクティスを適用し、開発者がより良いコードを書けるよう支援します。 - ベストプラクティスへの準拠という観点からコードをレビューする - ドメインのパターンに基づいて改善案を提案する - 特定のアプローチが推奨される理由を説明する - コードを標準に沿うようリファクタリングする - アーキテクチャに関するガイダンスを提供する ### TypeScript エキスパートJavaScript のコードスタイルと構成
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- コードスタイルと構成
- 命名規則
- JavaScript の使用
JSDoc による JavaScript のドキュメント作成
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- JSDoc コメント:JavaScript とモダンな ES6 構文には JSDoc コメントを使用します。
JavaScript/TypeScript のコードスタイル
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- 簡潔で技術的に正確な JavaScript/TypeScript コードと例を記述します
- モダンな JavaScript の機能とベストプラクティスを使用します
- 関数型プログラミングのパターンを優先し、クラスの使用を最小限に抑えます
- 説明的な変数名を使用します(例:isExtensionEnabled、hasPermission)
JavaScript/TypeScript のコーディング標準
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- JavaScript と TypeScript を記述する際は、常に WordPress のコーディング標準を使用します。
- JavaScript より TypeScript を優先します。
JavaScript/TypeScript のコーディングスタイル
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- 純粋関数には
functionキーワードを使用します。セミコロンは省略します。 - すべてのコードで TypeScript を使用します。
typeよりinterfaceを優先します。enumは避け、マップを使用します。 - ファイルの構成:エクスポートするコンポーネント、サブコンポーネント、ヘルパー、静的コンテンツ、型。
- 条件文では不要な波括弧を避けます。
- 条件文内の単一行の文では、波括弧を省略します。
- 単純な条件文には簡潔な一行構文を使用します(例:if (condition) doSomething())。
TypeScript コード生成ルール
コードをレビューまたは作成する際は、次のガイドラインを適用します。
- 型安全性を確保するため、常に TypeScript を使用します。適切な型定義とインターフェースを指定します。
- コンポーネントは関数コンポーネントとして実装し、状態管理が必要な場合はフックを使用します。
- 複雑なロジックや設計上の判断を説明する、明確で簡潔なコメントを記述します。
- Next.js 14 のベストプラクティスに沿った、適切なファイル構成と命名規則を提案します。
'use client'ディレクティブは、必要な場合にのみ使用します。
TypeScript 5.5~5.8 の機能(2025~2026)
TypeScript コードを作成またはレビューする際は、これらの最新機能を適用します。
推論される型述語(TS 5.5)
TypeScript は、関数本体から型述語を推論するようになりました。単純なフィルターでは、x is T を手動で注釈する必要はありません。
// Before 5.5 — manual predicate required
const strings = values.filter((v): v is string => v !== null && typeof v === 'string');
// TS 5.5+ — predicate is inferred automatically
const strings = values.filter(v => v !== null && typeof v === 'string'); // string[]
推論が曖昧な場合を除き、型述語を手書きするよりも TypeScript に推論させることを優先します。
分離された宣言(TS 5.5)
ライブラリや共有パッケージでは、tsconfig で "isolatedDeclarations": true を有効にします。これにより、すべてのエクスポートされたシンボルに明示的な型注釈が必要となり、サードパーティ製ツール(esbuild、oxc)が tsc を実行せずに並列で .d.ts を生成できるようになります。
// Required when isolatedDeclarations: true
export function add(a: number, b: number): number {
return a + b;
}
// Omitting the return type annotation is an error under isolatedDeclarations
公開するパッケージやモノレポの共有ライブラリでは、isolatedDeclarations を使用します。インクリメンタルビルドのパフォーマンスも向上します。
初期化されない変数のチェック(TS 5.7)
TS 5.7 は、内側の関数を介してアクセスされる場合でも、どのコードパスでも代入されないまま宣言された変数を検出します。
// TS 5.7 reports error: 'result' has no initializer and is never assigned
function compute() {
let result: number;
printResult();
function printResult() {
console.log(result);
} // error
}
strict: true を維持することで、この機能を有効にします。追加のフラグは不要です。
--erasableSyntaxOnly(TS 5.8)
ネイティブの TypeScript 消去機能を使用する Node.js プロジェクト(--experimental-strip-types を使う Node 22.6 以降、または Node 23 以降)では、tsconfig に "erasableSyntaxOnly": true を追加します。このフラグにより、enum、namespace、コンストラクターのパラメーター・プロパティがコンパイルエラーになります。
// All three are errors under erasableSyntaxOnly: true
enum Status {
Active,
Inactive,
} // error — use const object instead
namespace Utils {
export const x = 1;
} // error — use a module instead
class Foo {
constructor(private x: string) {}
} // error — assign manually
推奨される置き換え方法:
// Enum → const object + typeof
const Status = { Active: 'active', Inactive: 'inactive' } as const;
type Status = (typeof Status)[keyof typeof Status];
// Parameter property → explicit assignment
class Foo {
private x: string;
constructor(x: string) {
this.x = x;
}
}
satisfies 演算子
オブジェクトを型に照らして検証しながら、リテラル型の推論を可能な限り狭く保つには、satisfies を使用します。
type Config = { env: 'dev' | 'prod'; retries: number };
// Plain annotation widens env to 'dev' | 'prod'
const cfg1: Config = { env: 'dev', retries: 3 };
// typeof cfg1.env → 'dev' | 'prod'
// satisfies keeps literal but still validates the shape
const cfg2 = { env: 'dev', retries: 3 } satisfies Config;
// typeof cfg2.env → 'dev' (narrower — use for keyof, typeof lookups)
主な用途:設定オブジェクト、i18n マップ、イベントハンドラーレジストリ、ルート定義。
const 型パラメーター(TS 5.0+)
ジェネリックに const を指定すると、各呼び出しで as const を指定しなくても、呼び出し元からリテラル型を推論できます。
// Without const — T infers as string[]
function identity<T>(value: T): T {
return value;
}
identity(['a', 'b']); // T = string[]
// With const — T infers as readonly ['a', 'b']
function identity<const T>(value: T): T {
return value;
}
identity(['a', 'b']); // T = readonly ['a', 'b']
タプルファクトリー、型付きルートビルダー、メソッドチェーンを使った API に便利です。
NoInfer ユーティリティ型(TS 5.4+)
NoInfer<T> を使用すると、あるパラメーターが推論元として使われるのを防ぎ、TypeScript が先に他の引数から T を解決するようにできます。
// Without NoInfer — TypeScript widens initial to string (wrong)
function createFSM<T extends string>(states: T[], initial: T): void {}
createFSM(['idle', 'running'], 'typo'); // no error — 'typo' widens T
// With NoInfer — initial must match inferred T from states
function createFSM<T extends string>(states: T[], initial: NoInfer<T>): void {}
createFSM(['idle', 'running'], 'typo'); // error — 'typo' not in T
Node 22+ 向けの tsconfig 推奨設定
Node.js 22+ のプロジェクト(ネイティブ ESM または CJS)では、以下の設定を使用します。
{
"compilerOptions": {
// Target Node 22 supports ES2023 natively
"target": "ES2023",
"lib": ["ES2023"],
// Native Node ESM (files use .ts extension, output .js/.mjs)
"module": "NodeNext",
"moduleResolution": "NodeNext",
// Strict + extras
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// TS 5.5+ — enforce explicit exports for parallel d.ts gen (libraries)
// "isolatedDeclarations": true,
// TS 5.8 — disallow enums/namespaces/param-props (Node strip-types compat)
// "erasableSyntaxOnly": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
},
}
バンドルするアプリ(Vite、webpack、esbuild)では、代わりに "module": "ESNext" と "moduleResolution": "bundler" を使用します。
ESM / CJS の相互運用に関するガイダンス
Node 22+ のプロジェクトでモジュールシステムのエラーを避けるには、以下のルールに従ってください。
-
typeフィールドがデフォルトを決定します。 package.json の"type": "module"は、.jsファイルを ESM として扱います。CJS をデフォルトにするには、typeを省略するか"commonjs"を設定します。 -
拡張子が常に優先されます。
.mjs→ ESM、.cjs→ CJS となり、typeの設定にかかわらず適用されます。 -
moduleResolution: NodeNextでは、相対インポートに明示的な拡張子が必要です。import { foo } from './foo.js'; // correct — .js even for .ts source import { bar } from './bar.cjs'; // correct for CJS output -
ESM から CJS を同期的に
require()することはできません。 ESM → CJS ではcreateRequireを使用します。CJS → ESM では動的なimport()を使用します。 -
デュアル公開(CJS + ESM): package.json の
exportsフィールドで"import"条件と"require"条件を使用します。tsc -p tsconfig.esm.jsonとtsc -p tsconfig.cjs.jsonでビルドします。 -
esModuleInterop: trueは、import構文で CJS モジュールをインポートし、デフォルトエクスポートを合成する場合に必要です。 -
バンドルするアプリでは、
"moduleResolution": "bundler"を使用します。これにより拡張子のないインポートが許可され、解決処理をバンドラーに任せられます。バンドルするプロジェクトでは"type": "module"を設定しないでください(このモードでは、TypeScript はバンドラーの CJS/ESM 相互運用を完全には解析できません)。
アンチパターン(使用しないでください)
- Enums — 代わりに
typeofと組み合わせたconstオブジェクトを使用します。Enums は実行時コードを生成し、ツリーシェイキングを妨げ、erasableSyntaxOnlyによって禁止されています。 namespace宣言 — ES モジュールを使用します。Namespaces は消去できないレガシーパターンです。any— 型ガードを使ったunknownを使用するか、型を適切にモデル化します。- 型アサーション(
as T) —satisfies、型ガード、または適切なジェネリックを優先します。 !による非 null アサーション —null/undefinedを明示的に処理します。- クラスのパラメーター・プロパティ — フィールドを明示的に代入します。
erasableSyntaxOnlyによって禁止されています。
スキルの統合
このエキスパートスキルは、次の 1 つの個別スキルを統合しています。
- typescript-expert
関連スキル
nodejs-expert- TypeScript を使用する Node.js バックエンドのパターン(Express、NestJS)
鉄則
- 必ず型エイリアスよりインターフェースを優先し、新しいコードには厳格な TypeScript コンパイラー設定を使用します
- 決して
any型を使用せず、適切な型注釈、unknown、またはジェネリックを使用します - 必ず
asによるキャストではなく、実行時の型の絞り込みに型ガードを使用します - 決してEnums を使用せず、ツリーシェイキングの向上と明確さのために const マップまたはリテラルユニオン型を使用します
- 必ず不変データを使った関数型パターンを適用し、関数で十分な場合はクラスベースのパターンを避けます
アンチパターン
| アンチパターン | 問題点 | 適切な対応 |
|---|---|---|
any 型をいたるところで使う | 型安全性を損ない、コンパイル時にバグを見逃します | unknown、ジェネリクス、または適切なインターフェースを使います |
| TypeScript の列挙型 | ツリーシェイキングが不十分で、実行時のオーバーヘッドがあり、出力も分かりにくくなります | const マップまたはリテラルユニオン型を使います |
as による型キャスト | 型チェックを回避し、誤った安心感を生みます | 型ガード(typeof、instanceof、判別子)を使います |
| クラス内で共有状態を変更可能にする | 挙動が予測しにくく、テストも困難になります | 不変データを用いた関数型パターンを使います |
| strict モードを使わない緩い tsconfig | 型エラーのカテゴリを丸ごと見逃します | すべての TypeScript 設定で "strict": true を有効にします |
メモリープロトコル(必須)
開始前:
cat .claude/context/memory/learnings.md
完了後: 新たに見つかったパターンや例外を記録します。
中断を想定してください。コンテキストがリセットされる場合があります。メモリーに記録されていないことは、実行されなかったことになります。