typescript について
typescriptは、TypeScript開発者向けのコーディングスキルです。定数、インターフェース、unknown値、ユーティリティ型、型ガード、関連するオプショナルプロパティの型安全なパターンを紹介します。
主な機能
- 01constオブジェクトから型を生成
- 02ネストデータ用の独立したインターフェース
- 03anyではなくunknownを使用
- 04TypeScriptユーティリティ型
- 05型ガードと判別可能なユニオン
活用シーン
- 01再利用可能なステータス型の定義
- 02ネストしたユーザーデータのモデル化
- 03無効なプロパティ組み合わせの防止
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ prowler-cloud/ prowler --skill typescriptインストール後、Claude Code で/typescriptを入力して読み込まれたか確認します。
詳細
Const Types パターン(必須)
// ✅ ALWAYS: Create const object first, then extract type
const STATUS = {
ACTIVE: "active",
INACTIVE: "inactive",
PENDING: "pending",
} as const;
type Status = (typeof STATUS)[keyof typeof STATUS];
// ❌ NEVER: Direct union types
type Status = "active" | "inactive" | "pending";
理由: 信頼できる唯一の情報源、実行時の値、オートコンプリート、リファクタリングの容易さを実現できます。
フラットなインターフェース(必須)
// ✅ ALWAYS: One level depth, nested objects → dedicated interface
interface UserAddress {
street: string;
city: string;
}
interface User {
id: string;
name: string;
address: UserAddress; // Reference, not inline
}
interface Admin extends User {
permissions: string[];
}
// ❌ NEVER: Inline nested objects
interface User {
address: { street: string; city: string }; // NO!
}
any は使用しない
// ✅ Use unknown for truly unknown types
function parse(input: unknown): User {
if (isUser(input)) return input;
throw new Error("Invalid input");
}
// ✅ Use generics for flexible types
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
// ❌ NEVER
function parse(input: any): any { }
ユーティリティ型
Pick<User, "id" | "name"> // Select fields
Omit<User, "id"> // Exclude fields
Partial<User> // All optional
Required<User> // All required
Readonly<User> // All readonly
Record<string, User> // Object type
Extract<Union, "a" | "b"> // Extract from union
Exclude<Union, "a"> // Exclude from union
NonNullable<T | null> // Remove null/undefined
ReturnType<typeof fn> // Function return type
Parameters<typeof fn> // Function params tuple
型ガード
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value
);
}
相互に関連するオプショナルなプロパティ(必須)
意味的に関連するプロパティを、互いに独立したオプショナルとしてモデル化しないでください。コンパイルは通るものの実行時に問題を引き起こす、不正な不完全状態が許容されてしまいます。判別共用体と never を使用して、不正な組み合わせを不可能にしてください。
// ❌ BEFORE: Independent optionals — half-states allowed
interface PaginationProps {
onPageChange?: (page: number) => void;
pageSize?: number;
currentPage?: number;
}
// ✅ AFTER: Discriminated union — shape is all-or-nothing
type ControlledPagination = {
controlled: true;
currentPage: number;
pageSize: number;
onPageChange: (page: number) => void;
};
type UncontrolledPagination = {
controlled: false;
currentPage?: never;
pageSize?: never;
onPageChange?: never;
};
type PaginationProps = ControlledPagination | UncontrolledPagination;
重要なルール: 2つ以上のプロパティが一緒にある場合にのみ意味を持つなら、それらは同じ判別共用体の分岐に属します。互いに独立したオプショナルとして組み合わせると、正しさを担保する責任が型システムから実行時のガードへと移ってしまいます。
型のインポート
import type { User } from "./types";
import { createUser, type Config } from "./utils";
コメント
Markdown 対応