MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
TypeScriptの基礎 - ジェネリクスの基本のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
TypeScriptの基礎 - ジェネリクスの基本
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ジェネリクス (Generics) とは、型をパラメータとして受け取ることで、型安全性を保ちながらコードの再利用性を高める機能である。<br> <br> ジェネリクスを使用しない場合、汎用的な関数やデータ構造を作るために <code>any</code> 型に頼ることが多くなり、型安全性が失われる。<br> ジェネリクスを使用することにより、使用時に具体的な型を指定しながらも、同じコードを様々な型に対して再利用できる。<br> <br> ジェネリクスの主な用途を以下に示す。<br> * 関数 *: 引数の型と戻り値の型を関連付けて、型安全な汎用関数を定義する。 * インターフェース *: 型パラメータを持つ汎用的なデータ構造を定義する。 * 型エイリアス *: オブジェクト型や関数型のジェネリックな定義を作成する。 * クラス *: 型パラメータを持つ汎用的なクラスを定義する。 <br> 型パラメータ名には慣習的に <code>T</code> (Type)、<code>U</code>、<code>V</code> 等の大文字の英字が使われるが、任意の名前を使用できる。<br> 複数の型パラメータを扱う場合は、<code>T</code>、<code>U</code> のように連続した文字を使用することが多い。<br> <br> また、意味を明確にする場合は、<code>TKey</code>、<code>TValue</code> のような名前も使用される。<br> <br><br> == ジェネリック関数 == ==== 基本的な構文 ==== ジェネリック関数は、関数名の後に型パラメータを <code><T></code> の形式で記述することで定義する。<br> 型パラメータ <code>T</code> は、引数の型と戻り値の型を関連付けるために使用する。<br> <br> 引数をそのまま返す最も基本的なジェネリック関数を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> function identity<T>(arg: T): T { return arg; } </syntaxhighlight> <br> アロー関数でジェネリクスを使用する場合は、<code><T></code> を引数リストの前に記述する。<br> <br> <syntaxhighlight lang="typescript"> const identity = <T>(arg: T): T => arg; </syntaxhighlight> <br> TSX (TypeScript + JSX) 環境では、<code><T></code> がJSXタグと誤解されることがある。<br> この問題を回避するため、型パラメータの末尾にトレーリングコンマを追加する。<br> <br> <syntaxhighlight lang="typescript"> // JSX環境では <T,> のようにトレーリングコンマを追加する const generic = <T,>(arg: T): T => arg; </syntaxhighlight> <br> TypeScript 5.0以降では、<code>const</code> 型パラメータを使用して、推論される型をリテラル型として保持できる。<br> <br> <syntaxhighlight lang="typescript"> // const型パラメータ - リテラル型を保持する (TypeScript 5.0以降) declare function fnGood<const T extends readonly string[]>(args: T): void; fnGood(["a", "b"]); // T は readonly ["a", "b"] として推論される </syntaxhighlight> <br> ==== 型引数の推論 ==== ジェネリック関数を呼び出す時、型引数を明示的に指定する方法と、コンパイラによる推論に任せる方法がある。<br> <br> <syntaxhighlight lang="typescript"> function identity<T>(arg: T): T { return arg; } // 型引数を明示的に指定する const result1 = identity<string>("hello!"); // resultの型 : string // 型推論に任せる (推奨) const result2 = identity("hello!"); // resultの型 : string (自動推論) const result3 = identity(42); // resultの型 : number (自動推論) </syntaxhighlight> <br> 多くの場合、コンパイラは渡された引数から型を自動的に推論できる。<br> 明示的な型指定は可読性を高める場合もあるが、型推論に任せる方が簡潔なコードになるため推奨される。<br> <br> 複雑な型を扱う場合 や 推論結果が意図と異なる場合に限り、明示的な型指定を使用することが望ましい。<br> <br> ==== 複数の型引数 ==== 複数の型パラメータが必要な場合は、カンマ区切りで複数の型引数を定義する。<br> <br> 2つの引数を受け取り、順序を入れ替えたタプルを返す関数を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> function swap<T, U>(a: T, b: U): [U, T] { return [b, a]; } const result = swap("hello", 42); // resultの型 : [number, string] </syntaxhighlight> <br> 2つの型パラメータを持つより実用的な例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> function zip<T, U>(arr1: T[], arr2: U[]): [T, U][] { return arr1.map((item, index) => [item, arr2[index]]); } const zipped = zip([1, 2, 3], ["a", "b", "c"]); // zippedの型 : [number, string][] </syntaxhighlight> <br> 複数の型引数を定義する際は、それぞれの型引数が実際に必要かどうかを確認する。<br> <br> 型引数が1か所でしか使用されない場合、ジェネリクスが本当に必要かどうかを再考することが推奨される。<br> <br><br> == ジェネリックインターフェース == ==== 基本的な使用方法 ==== インターフェースにも型パラメータを定義できる。<br> これにより、様々な型の値を保持する汎用的なデータ構造を定義できる。<br> <br> <syntaxhighlight lang="typescript"> interface Box<Type> { contents: Type; } // string型のBoxを宣言する let stringBox: Box<string>; // number型のBoxを宣言する let numberBox: Box<number>; </syntaxhighlight> <br> 複数の型パラメータを持つインターフェースの例を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> interface Pair<K, V> { key: K; value: V; } const pair: Pair<string, number> = { key: "age", value: 25 }; </syntaxhighlight> <br> ==== ジェネリックインターフェースの実装 ==== クラスがジェネリックインターフェースを実装する時は、<code>implements</code> キーワードとともに型パラメータを指定する。<br> <br> <syntaxhighlight lang="typescript"> interface Storage<T> { get(): T; set(value: T): void; } class GenericStorage<T> implements Storage<T> { private value: T; constructor(initialValue: T) { this.value = initialValue; } get(): T { return this.value; } set(value: T): void { this.value = value; } } const storage = new GenericStorage<string>("初期値"); console.log(storage.get()); // "初期値" storage.set("新しい値"); console.log(storage.get()); // "新しい値" </syntaxhighlight> <br> クラスに型パラメータを宣言することにより、インスタンス化時に具体的な型を指定できる。<br> <br> インターフェースとクラスの両方に同じ型パラメータを使用することで、型の整合性を保てる。<br> <br><br> == ジェネリック型エイリアス == ==== オブジェクト型のジェネリクス ==== <code>type</code> キーワードでも型パラメータを持つ型エイリアスを定義できる。<br> <br> <syntaxhighlight lang="typescript"> type Container<T> = { value: T }; const stringContainer: Container<string> = { value: "hello" }; const numberContainer: Container<number> = { value: 42 }; </syntaxhighlight> <br> ユニオン型やその他の型と組み合わせて、より複雑な型を定義することもできる。<br> <br> <syntaxhighlight lang="typescript"> // nullを許容するジェネリック型 type OrNull<Type> = Type | null; // 単一の値または配列を許容するジェネリック型 type OneOrMany<Type> = Type | Type[]; const value1: OrNull<string> = "hello"; const value2: OrNull<string> = null; const value3: OneOrMany<number> = 42; const value4: OneOrMany<number> = [1, 2, 3]; </syntaxhighlight> <br> ==== 関数型のジェネリクス ==== 型エイリアスを使用して、ジェネリックな関数型を定義できる。<br> <br> <syntaxhighlight lang="typescript"> // 入力型と出力型を型パラメータとして持つマッパー関数型 type Mapper<T, U> = (input: T) => U; // 同じ型を入力・出力とするトランスフォーマー関数型 type Transformer<T> = (input: T) => T; // 具体的な型を指定して使用する const stringify: Mapper<number, string> = (n) => n.toString(); const double: Transformer<number> = (n) => n * 2; console.log(stringify(42)); // "42" console.log(double(21)); // 42 </syntaxhighlight> <br> ジェネリックな関数型エイリアスを使用することにより、関数のシグネチャを再利用可能な形で定義できる。<br> <br> コールバック関数を受け取る高階関数の引数型定義にも活用できる。<br> <br><br> == 型引数のデフォルト値 == 型パラメータにデフォルト値を指定することにより、型引数を省略した場合に使用する型を定義できる。<br> <br> デフォルト値を持つ型パラメータは、型引数を省略した場合にデフォルト型が使用される。<br> <br> <syntaxhighlight lang="typescript"> type Container<T = string> = { value: T }; // 型引数を省略するとstring型が使用される const stringContainer: Container = { value: "hello" }; // 型引数を明示的に指定する const numberContainer: Container<number> = { value: 42 }; </syntaxhighlight> <br> 型制約 (<code>extends</code>) とデフォルト値を組み合わせることもできる。<br> <br> <syntaxhighlight lang="typescript"> // 制約とデフォルト値を組み合わせる interface Container<T extends string | number = string> { value: T; } // 型引数を省略するとstring型が使用される const defaultContainer: Container = { value: "hello" }; // 制約を満たす型を指定できる const numberContainer: Container<number> = { value: 42 }; // 制約を満たさない型はエラーになる // const boolContainer: Container<boolean> = { value: true }; // エラー </syntaxhighlight> <br> デフォルト値を持つ型パラメータは、デフォルト値を持たない型パラメータより後に配置する必要がある。<br> <br> ジェネリックなコンポーネントやユーティリティ型において、使用頻度の高い型をデフォルトとして設定することにより、使用する側のコードを簡潔に保てる。<br> <br><br> == 実用的なパターン == ==== React Hooksでの使用例 ==== ReactのHooksはジェネリクスを積極的に活用しており、状態の型を明示的に指定できる。<br> <br> <code>useState</code> は型パラメータを受け取り、状態と更新関数の型を定義する。<br> <br> <syntaxhighlight lang="typescript"> // useStateにジェネリクスを使用する const [user, setUser] = useState<User | null>(null); // 型推論が可能な場合は省略できる const [count, setCount] = useState(0); // number型として推論される </syntaxhighlight> <br> <code>useReducer</code> では、状態型とアクション型をそれぞれ型パラメータで指定できる。<br> 判別可能なユニオン型を使用したアクション定義との組み合わせが一般的である。<br> <br> <syntaxhighlight lang="typescript"> interface State { count: number; loading: boolean; } type Action = | { type: "INCREMENT" } | { type: "DECREMENT" } | { type: "SET_LOADING"; payload: boolean }; function reducer(state: State, action: Action): State { switch (action.type) { case "INCREMENT": return { ...state, count: state.count + 1 }; case "DECREMENT": return { ...state, count: state.count - 1 }; case "SET_LOADING": return { ...state, loading: action.payload }; } } // useReducerはreducerの引数・戻り値から型を推論する const [state, dispatch] = useReducer(reducer, { count: 0, loading: false }); </syntaxhighlight> <br> カスタムフックでジェネリクスを使用することにより、汎用的なデータ取得フックを定義できる。<br> <br> <syntaxhighlight lang="typescript"> interface Post { id: number; title: string; body: string; } function useFetch<T>(url: string): { data: T | null; loading: boolean; error: Error | null; } { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState<Error | null>(null); // fetchロジック // ...略 return { data, loading, error }; } // 使用例 : Post型のデータを取得する const { data: post, loading } = useFetch<Post>("/api/posts/1"); </syntaxhighlight> <br> ==== Tauriのinvokeでの使用例 ==== Tauriでは、<code>invoke</code> 関数にジェネリクスを使用して、Rustバックエンドからの戻り値の型を安全に扱える。<br> <br> <syntaxhighlight lang="typescript"> import { invoke } from "@tauri-apps/api/tauri"; interface UserData { id: number; username: string; email: string; } // invoke<T>でRustコマンドの戻り値の型を指定する async function fetchUser(userId: number): Promise<UserData> { return invoke<UserData>("fetch_user", { userId }); } // 使用例 const user = await fetchUser(1); console.log(user.username); // 型安全にプロパティにアクセスできる </syntaxhighlight> <br> <code>invoke<T></code> に型パラメータを指定することでコマンドの戻り値を正確な型として扱えるため、<br> コンパイル時に型安全性を保証しながらRustとTypeScript間のデータのやり取りを記述できる。<br> <br><br> == 関連情報 == * [[TypeScriptの基礎 - ジェネリクスの制約]] * [[TypeScriptの基礎 - ユーティリティ型(基本)]] * [[TypeScriptの基礎 - ユーティリティ型(応用)]] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Rust]][[カテゴリ:Web]]
TypeScriptの基礎 - ジェネリクスの基本
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse