typescript-variables について
TypeScriptの変数に関するスタイル指針を、開発タスクに応じて適用、レビュー、説明するスキルです。constアサーション、ユニオン型、nullとundefinedの使い分けを扱います。
主な機能
- 01タスクに応じた変数規約の適用
- 02constアサーションの優先
- 03リテラルユニオン型の活用
- 04複数の真偽値による状態表現の回避
- 05nullとundefinedの区別
活用シーン
- 01定数オブジェクトや配列のリテラル型保持
- 02ユニオン型による排他的状態の表現
- 03値が未指定か空かの明確化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mkosir/ typescript-style-guide --skill typescript-variablesインストール後、Claude Code で/typescript-variablesを入力して読み込まれたか確認します。
詳細
変数
現在のタスクの状況に合わせて、TypeScript スタイルガイドの変数に関する規約を適用してください。
ワークフロー
- 対象リポジトリで使用されている規約と設定を確認します。
- リポジトリで明示されている規約がある場合は、この意見に基づくガイドラインより優先します。
- タスクに関係するガイドラインのみを適用、確認、または説明します。
- 適切な選択が状況や判断によって異なる場合は、重要なトレードオフを示します。
適用範囲
- 自動で適用できるチェックは、TypeScript と ESLint に任せます。
- このガイドが有効だからといって、関係のない TypeScript スタイルガイドの規約を適用しないでください。
関連ガイダンス
アプリケーションの状態
異なるデータを必要とする状態について詳しくは、利用可能であれば typescript-discriminated-unions を参照してください。
変数
const アサーション
定数は as const の const アサーションを使って宣言するよう努めてください。
定数は変更を意図しない値を表すために使われ、コードベースの信頼性と一貫性を高めます。const アサーションはリテラル型を保持し、読み取り専用のプロパティを推論します。
- 型の絞り込み —
as constを使うと、リテラル値(数値や文字列など)が、numberやstringのような一般化された型ではなく、厳密な値として扱われます。 - 読み取り専用プロパティ — オブジェクトと配列のプロパティが読み取り専用になり、TypeScript が直接の変更を検出します。
例:
-
オブジェクト
// ❌ Avoid const FOO_LOCATION = { x: 50, y: 130 }; // Type { x: number; y: number; } FOO_LOCATION.x = 10; // ✅ Use const FOO_LOCATION = { x: 50, y: 130 } as const; // Type '{ readonly x: 50; readonly y: 130; }' FOO_LOCATION.x = 10; // Error -
配列
// ❌ Avoid const BAR_LOCATION = [50, 130]; // Type number[] BAR_LOCATION.push(10); // ✅ Use const BAR_LOCATION = [50, 130] as const; // Type 'readonly [50, 130]' BAR_LOCATION.push(10); // Error -
テンプレートリテラル
// ❌ Avoid const RATE_LIMIT = 25; const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.`; // Type string // ✅ Use const RATE_LIMIT = 25; const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.` as const; // Type 'Max number of requests/min is 25.'
enum と const アサーション
enum は、実行時コストや特有の問題があるため、TypeScript エコシステムでは推奨されません。
TypeScript のドキュメントでは、いくつかの落とし穴が説明されています。また、TypeScript 5.8 では、enum など実行時コードを生成する機能を無効にする --erasableSyntaxOnly フラグが導入されました。
{'no-restricted-syntax': [ 'error', { selector: 'TSEnumDeclaration', message: 'Replace enum with a literal type or a const assertion.', }, ]}
一般的には、次の方法を優先してください。
- 可能な場合はリテラル型を使います。
- 値をループ処理する場合は、const アサーションを付けた配列を使います。
- 任意の値を列挙する場合は、const アサーションを付けたオブジェクトを使います。
例:
-
実行時オブジェクトを避け、バンドルサイズを削減するには、リテラル型を使います。
// ❌ Avoid using enums as they increase the bundle size enum UserRole { GUEST = 'guest', MODERATOR = 'moderator', ADMINISTRATOR = 'administrator', } // Transpiled JavaScript ('use strict'); var UserRole; (function (UserRole) { UserRole['GUEST'] = 'guest'; UserRole['MODERATOR'] = 'moderator'; UserRole['ADMINISTRATOR'] = 'administrator'; })(UserRole || (UserRole = {})); // ✅ Use literal types - Types are stripped during transpilation type UserRole = 'guest' | 'moderator' | 'administrator'; const isGuest = (role: UserRole) => role === 'guest'; -
値をループ処理する場合は、const アサーションを付けた配列を使います。
// ❌ Avoid using enums enum USER_ROLES { guest = 'guest', moderator = 'moderator', administrator = 'administrator', } // ✅ Use const assertions arrays const USER_ROLES = ['guest', 'moderator', 'administrator'] as const; type UserRole = (typeof USER_ROLES)[number]; const seedDatabase = () => { USER_ROLES.forEach((role) => { db.roles.insert(role); } } const insert = (role: UserRole) => {... const UsersRoleList = () => { return ( <div> {USER_ROLES.map((role) => ( <Item key={role} role={role} /> ))} </div> ); }; const Item = ({ role }: { role: UserRole }) => {... -
任意の値を列挙する場合は、const アサーションを付けたオブジェクトを使います。
// ❌ Avoid using enums enum COLORS { primary = '#B33930', secondary = '#113A5C', brand = '#9C0E7D', } // ✅ Use const assertions objects const COLORS = { primary: '#B33930', secondary: '#113A5C', brand: '#9C0E7D', } as const; type Colors = typeof COLORS; type ColorKey = keyof Colors; // Type "primary" | "secondary" | "brand" type ColorValue = Colors[ColorKey]; // Type "#B33930" | "#113A5C" | "#9C0E7D" const setColor = (color: ColorValue) => {... setColor(COLORS.primary); setColor('#B33930');
型のユニオンとブールフラグ
複数の選択肢が相互に排他的な場合は特に、ブール型のフラグ変数を複数使うのではなく、型のユニオンを活用してください。
ブールフラグは時間とともに増えやすく、アプリケーションの実際の状態が見えにくくなるため、コードが分かりにくく、エラーも起こりやすくなります。
// ❌ Avoid introducing multiple boolean flag variables
const isPending, isProcessing, isConfirmed, isExpired;
// ✅ Use type union variable
type UserStatus = 'pending' | 'processing' | 'confirmed' | 'expired';
const userStatus: UserStatus;
状態値だけが変わる場合はリテラルユニオンを使います。それぞれの状態で異なるデータが必要な場合は、判別可能ユニオンを使って有効な状態を明示的に表現してください。
null と undefined
strictNullChecks を有効にすると、null と undefined はそれぞれ異なる型と意味を持ちます。アプリケーションにおける値の不在の意味に応じて、一貫して使い分けてください。
次のようにすることを推奨します。
- 代入や関数の戻り値など、値が明示的に空であることを表す場合は
nullを使います。 - フォームのオプショナルフィールド、リクエストペイロード、データベースクエリなど、値が欠落または省略されていることを表す場合は
undefinedを使います(Prisma の使い分け)。