TypeSafe とより具体的な型指定例のための TypeScript でのジェネリック型パラメーターと型注釈の使用
関数シグネチャの一般化:
関連する関数の引数の作成:
タプル型の使用:
関係性のある絞り込みタイプ:
汎用インスタンス化:
未知のものを取り除く:
ジェネリックインスタンス化を理解する:
汎用関数:
ジェネリック医薬品のメリット:
ジェネリック医薬品を使用する場合:
フィルタロジックの作成:
リセット機能:
サブタイプに優しいコード:
共用体型のジェネリック型パラメータ:
新しいオブジェクトタイプの生成:
グループのタイプアノテーション:
おもちゃにレンガの種類を追加する:
groupToys機能のアップデート:
おもちゃのグループ化の最適化:
グループ化パターンの一般化:
アサーション署名を使用したオブジェクトの変更:
型アサーションとアサート関数:
アサーション署名の使用:
型マップを使用した型のマッピング:
ファクトリ関数と型マップ:
HTMLElementTagNameMap の拡張:
ThisType を使用してオブジェクト内で this を定義する:
問題:
解決:
議論:
解説する
TypeScriptを使用する際、特定の文字列リテラルをリテルタイプとして固定し、型マップから正しいHTML要素のバリアントをインデックスで参照するためにジェネリクスを使用することができます。また、document.createElement
を使用する際は、2つの型アサーション(型指定の強制)が必要です。1つはセットを広げるためのものです(Tを文字列に)、もう1つはセットを狭めるためのものです(HTMLElementをAllElements[T]に)。これらのアサーションは、第3.9レシピにおいて確立されたように、制御外のAPIを扱っていることを示しています。これらのアサーションについては後ほど扱います。
さらに、HTMLAnchorElementにhrefを設定するなど、指定したHTML要素に追加のプロパティを渡すオプションを提供したいと思います。これらのプロパティはすでに各HTMLElementバリアンツに存在しますが、必須ではなくオプショナルにする必要があります。既存の型のすべてのプロパティを任意のものとするには、組み込み型のPartial<T>
を使います。これはマップされた型で、特定の型の全てのプロパティを取得し、そこに型修飾子を追加します。
対案を考える。
ファクトリ関数は、基本的な情報に基づいて複雑なオブジェクトのバリアントを作成したい場合に適しています。ブラウザのJavaScriptで知られている一つのシナリオは、要素の作成です。document.createElement
関数は要素のタグ名を受け取り、必要なすべてのプロパティを変更できるオブジェクトを返します。
ここで、createElement
という整ったファクトリ関数を作成して、この作成プロセスをもっと手軽にします。この関数は要素のタグ名を取るだけでなく、個々のプロパティを一つひとつ設定する必要がないように、プロパティのリストも作成します:
function createElement<K extends keyof HTMLElementTagNameMap>( tagName: K, props?: Partial<HTMLElementTagNameMap[K]> ): HTMLElementTagNameMap[K] { const element = document.createElement(tagName) as HTMLElementTagNameMap[K]; if (props) { Object.keys(props).forEach(key => { element[key] = props[key]; }); } return element; } // 使用例 const anchor = createElement('a', { href: 'https://www.example.com', target: '_blank' }); document.body.appendChild(anchor``` この関数はジェネリクスKを使用しており、`HTMLElementTagNameMap`からタグ名に対応する要素タイプを導出しています。`props?`引数はオプショナルなので、設定したいプロパティだけを渡すことができます。各プロパティは`Partial`型を使って任意になっており、必要なものだけを含めることができるようになります。ファクトリ関数を使用することで、要素の作成と設定が、より宣言的で読みやすく、そして使いやすくなります。
解説する
ファクトリ関数は、いくつかの基本情報に基づいて複雑なオブジェクトの異なるバリエーションを作成したい場合に非常に適しています。ブラウザJavaScriptでよく知られているのは、要素の生成のシナリオです。document.createElement
関数は、要素のタグ名を引数にとり、必要なすべてのプロパティを変更できるオブジェクトを生成します。
この生成プロセスをさらに便利にするために、createElement
と呼ばれる洗練されたファクトリ関数を作りたいとします。この関数は要素のタグ名だけでなく、プロパティのリストも受け取るので、各プパティを個々に設定する手間が省けます。
以下に簡単なコード例を示します。
function createElement<K extends keyof HTMLElementTagNameMap>( tagName: K, props?: Partial<HTMLElementTagNameMap[K]> ): HTMLElementTagNameMap[K] { // 指定されたタグ名で要素を作成 const element = document.createElement(tagName) as HTMLElementTagNameMap[K]; // オプショナルなpropsが提供された場合、それらのプロパティを要素に適用する if (props) { Object.keys(props).forEach(key => { (element as any)[key] = props[key]; }); } // 完成した要素を返す return element; } // 使用例 const anchor = createElement('a', { href: 'https://www.example.com', target: '_blank' }); document.body.appendChild(anchor);
この関数では、カスタムのHTML要素タイプを作成する際、ジェネリック型K
を使ってHTMLElementTagNameMap
から対応する要素の型を引き出します。第二引数のprops
はPartial
を用いることで、これらのプロパティを任意とします。これにより、作成した要素に適用したいプロパティのみを提供することができます。
このcreateElement
ファクトリ関数を利用することで、要素の作成とプロパティ設定が宣言的で読みやすく、簡単に行えるようになります。