MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
TypeScriptの基礎 - ユーティリティ型(応用)のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
TypeScriptの基礎 - ユーティリティ型(応用)
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 応用的なユーティリティ型とは、TypeScriptが標準で提供するジェネリック型のうち、条件型 (Conditional Types) と <code>infer</code> キーワードを基盤として構築された、<br> より高度な型操作を行うための型である。<br> <br> 基本的なユーティリティ型 (<code>Partial</code>、<code>Required</code>、<code>Readonly</code> 等) がオブジェクト型のプロパティを変換するのに対し、<br> 応用的なユーティリティ型は関数の戻り値型や引数型の抽出、Promiseが解決した後の型の取得、ユニオン型のフィルタリング等を実現する。<br> <br> これらのユーティリティ型を活用することにより、ライブラリや外部モジュールの型定義から必要な型情報を安全に抽出できる。<br> 型を明示的に再定義する必要がなくなり、型定義の変更に追随した保守性の高いコードを記述できる。<br> <br> 基本的なユーティリティ型の詳細については、[[TypeScriptの基礎 - ユーティリティ型(基本)]]のページを参照すること。<br> <br> <center> {| class="wikitable" |+ 応用ユーティリティ型の一覧 ! ユーティリティ型 !! 概要 |- | <code>ReturnType<T></code> || 関数型 <code>T</code> の戻り値の型を取得する |- | <code>Parameters<T></code> || 関数型 <code>T</code> の引数の型をタプルとして取得する |- | <code>Awaited<T></code> || <code>Promise</code> 型 <code>T</code> が解決された後の型を再帰的に取得する |- | <code>Extract<T, U></code> || ユニオン型 <code>T</code> から型 <code>U</code> に代入可能な型のみを抽出する |- | <code>Exclude<T, U></code> || ユニオン型 <code>T</code> から型 <code>U</code> に代入可能な型を除外する |- | <code>NonNullable<T></code> || 型 <code>T</code> から <code>null</code> と <code>undefined</code> を除外する |} </center> <br><br> == ReturnType<T> == <code>ReturnType<T></code> は、関数型 <code>T</code> の戻り値の型を取得するユーティリティ型である。<br> <br> 関数の実装を変更した際に、戻り値の型を別途更新する必要がなくなり、型定義の一元管理が可能になる。<br> <br> ==== 内部定義 ==== <code>ReturnType<T></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any; </syntaxhighlight> <br> <code>T extends (...args: any) => infer R</code> という条件型により、関数型の戻り値の部分を <code>infer R</code> でキャプチャする。<br> <br> 条件が成立する場合は <code>R</code> が、成立しない場合は <code>any</code> が返される。<br> <br> ==== 実用例 ==== <code>typeof</code> 演算子と組み合わせることにより、既存の関数から型情報を抽出できる。<br> <br> <syntaxhighlight lang="typescript"> function getUser(id: string) { return { id, name: "Alice", email: "alice@example.com" }; } type User = ReturnType<typeof getUser>; // { id: string; name: string; email: string } </syntaxhighlight> <br> ジェネリック関数の戻り値型も取得できる。<br> <br> <syntaxhighlight lang="typescript"> function createArray<T>(item: T): T[] { return [item]; } type StringArray = ReturnType<typeof createArray<string>>; // string[] </syntaxhighlight> <br> 非同期関数に <code>ReturnType<T></code> を適用すると <code>Promise<T></code> が返るため、解決後の型を得るには後述の <code>Awaited<T></code> と組み合わせる必要がある。<br> <br><br> == Parameters<T> == <code>Parameters<T></code> は、関数型Tの引数の型をタプル型として取得するユーティリティ型である。<br> <br> 関数の引数型を再利用してラッパー関数を定義する際に有用であり、元の関数の引数型の変更に追随できる。<br> <br> ==== 内部定義 ==== <code>Parameters<T></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never; </syntaxhighlight> <br> <code>infer P</code> により関数の引数リスト全体をタプル型としてキャプチャする。<br> 関数型でない場合は <u>never</u> が返される。<br> <br> ==== 実用例 ==== <code>Parameters<T></code> と <code>ReturnType<T></code> を組み合わせることにより、元の関数と同じシグネチャを持つラッパー関数を型安全に作成できる。<br> <br> 以下の例では、<u>loggedAdd</u> は <u>(a: number, b: number) => number</u> 型として推論されるため、型安全にラッパー関数を定義できる。<br> <br> <syntaxhighlight lang="typescript"> function createLogger<T extends (...args: any[]) => any>(fn: T) { return function logged(...args: Parameters<T>): ReturnType<T> { console.log(`Calling with args:`, args); const result = fn(...args); console.log(`Result:`, result); return result; }; } const add = (a: number, b: number) => a + b; const loggedAdd = createLogger(add); loggedAdd(5, 3); // 型安全に呼び出せる </syntaxhighlight> <br><br> == Awaited<T> == <code>Awaited<T></code> は、<code>Promise</code> 型が解決された後の型を再帰的に取得するユーティリティ型である。<br> <br> TypeScript 4.5で導入されており、ネストした <code>Promise</code> 型も再帰的に解決できる。<br> <br> ==== 内部定義 ==== <code>Awaited<T></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type Awaited<T> = T extends null | undefined ? T : T extends object & { then(onfulfilled: infer F): any } ? F extends (value: infer V) => any ? Awaited<V> : never : T; </syntaxhighlight> <br> <u>null</u> と <u>undefined</u> はそのまま返し、thenableオブジェクト (Promiseライクなオブジェクト) に対しては、<code>then</code> メソッドのコールバック引数型を再帰的に解決する。<br> <br> ==== 基本的な使用例 ==== <code>Awaited<T></code> の基本的な挙動を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type A = Awaited<Promise<string>>; // string type B = Awaited<Promise<Promise<number>>>; // number (再帰的に解決) type C = Awaited<string | Promise<number>>; // string | number </syntaxhighlight> <br> ==== ReturnType<T>との組み合わせ ==== 非同期関数の戻り値型を取得する場合は、<code>ReturnType<T></code> と <code>Awaited<T></code> を組み合わせて使用する。<br> <br> <syntaxhighlight lang="typescript"> async function getUser(id: string) { return { id, name: "Alice" }; } // ReturnType単体ではPromise<{ id: string; name: string }>になる type UserPromise = ReturnType<typeof getUser>; // Promise<{ id: string; name: string }> // Awaitedと組み合わせることでPromiseを解決した型を得る type User = Awaited<ReturnType<typeof getUser>>; // { id: string; name: string } </syntaxhighlight> <br> <u><code>Awaited<ReturnType<typeof <関数名>>></code> というパターンは、非同期関数の解決後の型を取得する時の定番の組み合わせである。</u><br> <br><br> == Extract<T, U> == <code>Extract<T, U></code> は、ユニオン型 <code>T</code> から型 <code>U</code> に代入可能な型のみを抽出するユーティリティ型である。<br> <u>ユニオン型から特定の型のサブセットを取り出す場合に使用する。</u><br> <br> ==== 内部定義 ==== <code>Extract<T, U></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type Extract<T, U> = T extends U ? T : never; </syntaxhighlight> <br> <u>分配条件型 (Distributive Conditional Types) の性質により、ユニオン型の各メンバーに対して条件型が個別に適用される。</u><br> <u><code>U</code> に代入可能な型は残り、代入不可能な型は <u>never</u> となって消去される。</u><br> <br> ==== 実用例 ==== * イベント型のユニオンから特定のイベントのみを抽出する例 *: <syntaxhighlight lang="typescript"> type EventType = "click" | "scroll" | "resize" | "keydown" | "keyup"; type KeyboardEvents = Extract<EventType, "keydown" | "keyup">; // "keydown" | "keyup" type MouseEvents = Extract<EventType, "click" | "scroll" | "resize">; // "click" | "scroll" | "resize" </syntaxhighlight> *: <br> * 関数型のみを抽出する例 *: <code>Extract<T, U></code> は <code>U</code> に代入可能であればよいため、スーパータイプとの比較も可能である。 *: <syntaxhighlight lang="typescript"> type T = Extract<string | number | (() => void), Function>; // () => void </syntaxhighlight> <br><br> == Exclude<T, U> == <code>Exclude<T, U></code> は、ユニオン型 <code>T</code> から型 <code>U</code> に代入可能な型を除外するユーティリティ型である。<br> <u><code>Extract<T, U></code> と逆の操作を行い、特定の型をユニオンから取り除く場合に使用する。</u><br> <br> ==== 内部定義 ==== <code>Exclude<T, U></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type Exclude<T, U> = T extends U ? never : T; </syntaxhighlight> <br> 分配条件型により各メンバーに個別に適用され、<code>U</code> に代入可能な型は <u>never</u> となって消去され、代入不可能な型のみが残る。<br> <br> ==== 実用例 ==== * ユニオン型から特定の値を除外する例 *: <syntaxhighlight lang="typescript"> type T0 = Exclude<"a" | "b" | "c", "a" | "c">; // "b" </syntaxhighlight> *: <br> * イベント型のユニオンからキーボードイベントを除外する例 *: <syntaxhighlight lang="typescript"> type AllEvents = "click" | "scroll" | "resize" | "keydown" | "keyup"; type NonKeyboardEvents = Exclude<AllEvents, "keydown" | "keyup">; // "click" | "scroll" | "resize" </syntaxhighlight> <br> <u><code>Extract<T, U></code> と <code>Exclude<T, U></code> の使い分けとして、</u><br> <u>残したい型が明確な場合は <code>Extract<T, U></code> を、除外したい型が明確な場合は <code>Exclude<T, U></code> を使用するとよい。</u><br> <br><br> == NonNullable<T> == <code>NonNullable<T></code> は、型Tから <u>null</u> と <u>undefined</u> を除外するユーティリティ型である。<br> <u><code>Exclude<T, U></code> の特殊ケースに相当し、null安全なコードを記述する場合に頻繁に使用する。</u><br> <br> ==== 内部定義 ==== <code>NonNullable<T></code> の内部定義を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type NonNullable<T> = T extends null | undefined ? never : T; </syntaxhighlight> <br> 条件型により、<u>null</u> と <u>undefined</u> のみを <u>never</u> に変換して除外する。<br> <br> ==== 基本的な使用例 ==== <code>NonNullable<T></code> の基本的な挙動を以下に示す。<br> <br> <syntaxhighlight lang="typescript"> type T0 = NonNullable<string | number | undefined>; // string | number type T1 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] </syntaxhighlight> <br> ==== 型ガード関数との組み合わせ ==== <code>NonNullable<T></code> は型ガード関数と組み合わせることにより、配列から <u>null</u> / <u>undefined</u> を型安全に除去できる。<br> <br> <syntaxhighlight lang="typescript"> function isDefined<T>(value: T | null | undefined): value is NonNullable<T> { return value !== null && value !== undefined; } const values: (string | number | null | undefined)[] = ["a", 1, null, undefined, "b"]; const definedValues = values.filter(isDefined); // definedValuesの型 : (string | number)[] </syntaxhighlight> <br> 上記の型ガード関数isDefinedは、<u>value is NonNullable<T></u> という型述語を持つため、<u>filter()</u> メソッドに渡した時にフィルタ後の配列の型が正確に推論される。<br> <br> 型ガード関数の詳細については、[[TypeScriptの基礎 - 型の絞り込み]]のページを参照すること。<br> <br><br> == ライブラリの型定義を読むパターン == TypeScriptプロジェクトでは、ライブラリの型定義ファイル (<code>@types</code> パッケージ) を読み解き、既存の型定義を活用することが保守性の向上につながる。<br> <br> <code>@types</code> パッケージは <code>node_modules/@types/</code> ディレクトリ以下に配置されており、DefinitelyTypedコミュニティによってメンテナンスされている。<br> <br> ==== React.ComponentPropsの活用 ==== Reactを使用するプロジェクトでは、<code>React.ComponentProps<T></code> を用いてコンポーネントやDOM要素のProps型を抽出できる。<br> <br> * コンポーネントのProps型を抽出する例 *: <syntaxhighlight lang="typescript"> import React from "react"; // コンポーネントのProps型を抽出 type ButtonProps = React.ComponentProps<typeof Button>; // DOM要素のProps型を抽出 type DivProps = React.ComponentProps<"div">; type InputProps = React.ComponentProps<"input">; </syntaxhighlight> *: <br> * 抽出したProps型を拡張してカスタムコンポーネントを定義する例 *: <syntaxhighlight lang="typescript"> // DOM要素を拡張したカスタムコンポーネント const CustomInput: React.FC<InputProps & { label: string }> = ({ label, ...inputProps }) => ( <div> <label>{label}</label> <input {...inputProps} /> </div> ); </syntaxhighlight> *: <br> * コンポーネントの特定のProps属性のみを抽出する例 *: <syntaxhighlight lang="typescript"> type IconNameProp = React.ComponentProps<typeof Icon>["name"]; // "home" | "settings" | "user" | "logout" </syntaxhighlight> <br> なお、<code>ComponentProps<T></code> の関連型として、以下に示すバリアントがある。<br> * <code>React.ComponentPropsWithRef<T></code> *: <code>ref</code> プロップを含むProps型を取得する。 *: <code>forwardRef</code> を使用するコンポーネントに使用する。 * <code>React.ComponentPropsWithoutRef<T></code> *: <code>ref</code> プロップを除いたProps型を取得する。 *: <code>ref</code> 転送が不要なコンポーネントに使用する。 <br> ==== typeof import()を使用したモジュール型の動的取得 ==== <code>typeof import()</code> を使用することにより、モジュール全体の型をランタイムインポートなしに取得できる。<br> <br> <syntaxhighlight lang="typescript"> // モジュール型の動的取得 type UtilsModule = typeof import("./utils"); type CalculateFunction = UtilsModule["calculate"]; </syntaxhighlight> <br> <u><code>typeof import()</code> は型レベルのみで動作し、ランタイムには影響しない。</u><br> <br> <u>実際のモジュールのインポートは行われないため、バンドルサイズに影響しない点がメリットである。</u><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