typescript-advanced-types について
TypeScript 開発者向けの高度な型システムのリファレンスです。再利用可能な型パターンから React のコード例まで扱います。
主な機能
- 01ジェネリック型と条件型
- 02マップ型とテンプレートリテラル型
- 03ユーティリティ型と型ガード
- 04React コンポーネントとフックのパターン
- 05型安全性のベストプラクティス
活用シーン
- 01ジェネリック型で再利用可能な関数を定義
- 02既存の型から派生型を作成
- 03React の props、フック、イベントに型を付与
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ thapaliyabikendra/ ai-artifacts --skill typescript-advanced-typesインストール後、Claude Code で/typescript-advanced-typesを入力して読み込まれたか確認します。
詳細
TypeScript の高度な型
堅牢で型安全なアプリケーションを構築するために、TypeScript の高度な型システムを習得しましょう。
ジェネリクス
// Basic generic function
function identity<T>(value: T): T {
return value;
}
// Generic with constraint
interface HasLength { length: number; }
function logLength<T extends HasLength>(item: T): T {
console.log(item.length);
return item;
}
// Multiple type parameters
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
条件型
// Basic conditional
type IsString<T> = T extends string ? true : false;
// Extract return type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
// Nested conditions
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
"object";
マップ型
// Make all properties readonly
type Readonly<T> = { readonly [P in keyof T]: T[P] };
// Make all properties optional
type Partial<T> = { [P in keyof T]?: T[P] };
// Key remapping
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
// Filter by type
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K]
};
テンプレートリテラル型
type EventName = "click" | "focus" | "blur";
type EventHandler = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"
// String manipulation
type Upper = Uppercase<"hello">; // "HELLO"
type Lower = Lowercase<"HELLO">; // "hello"
type Cap = Capitalize<"john">; // "John"
ユーティリティ型
// Built-in utilities
type PartialUser = Partial<User>; // All optional
type RequiredUser = Required<PartialUser>; // All required
type ReadonlyUser = Readonly<User>; // All readonly
type NameEmail = Pick<User, "name" | "email">; // Select props
type NoPassword = Omit<User, "password">; // Remove props
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
type T3 = NonNullable<string | null>; // string
type PageInfo = Record<"home" | "about", { title: string }>;
React の TypeScript パターン
ジェネリックコンポーネント
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyExtractor: (item: T) => string;
}
function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
return (
<ul>
{items.map(item => (
<li key={keyExtractor(item)}>{renderItem(item)}</li>
))}
</ul>
);
}
型付きフック
type ApiState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: string };
function useApiState<T>() {
const [state, setState] = useState<ApiState<T>>({ status: 'idle' });
return { state, setLoading, setSuccess, setError };
}
型安全なコンテキスト
interface AuthContextValue {
user: UserDto | null;
login: (credentials: LoginDto) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextValue | null>(null);
function useAuth(): AuthContextValue {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within AuthProvider');
return context;
}
イベントハンドラーの型
// Form submit
const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
e.preventDefault();
};
// Input change
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
console.log(e.target.value);
};
// Button click
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
console.log(e.currentTarget.name);
};
よく使われるイベント型
| イベント | 型 |
|---|---|
| フォーム送信 | React.FormEventHandler<HTMLFormElement> |
| 入力変更 | React.ChangeEventHandler<HTMLInputElement> |
| ボタンクリック | React.MouseEventHandler<HTMLButtonElement> |
| キー押下 | React.KeyboardEventHandler<HTMLInputElement> |
| フォーカス | React.FocusEventHandler<HTMLInputElement> |
Ref の型
const inputRef = useRef<HTMLInputElement>(null);
// Forward ref
const Input = forwardRef<HTMLInputElement, InputProps>(
({ label, ...props }, ref) => (
<input ref={ref} {...props} />
)
);
Children の Props
interface CardProps {
children: React.ReactNode;
title: string;
}
// Render prop
interface DataFetcherProps<T> {
url: string;
children: (data: T, loading: boolean) => React.ReactNode;
}
型ガード
function isString(value: unknown): value is string {
return typeof value === "string";
}
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") throw new Error("Not a string");
}
ベストプラクティス
anyよりunknownを使う - 型チェックを強制します- オブジェクトには
interfaceを優先する - エラーメッセージがわかりやすくなります - ユニオンには
typeを使う - より柔軟です - 型推論を活用する - 可能な場合は TypeScript の型推論に任せます
- ヘルパー型を作成する - 再利用可能なユーティリティを構築します
- const アサーションを使う - リテラル型を保持します
- 型アサーションを避ける - 代わりに型ガードを使います
- strict モードを有効にする - すべての strict オプションを有効にします
詳細なリファレンス
包括的なパターンについては、以下を参照してください。
リソース
- TypeScript Handbook:https://www.typescriptlang.org/docs/handbook/
- Type Challenges:https://github.com/type-challenges/type-challenges
コメント
Markdown 対応