プレディケート(真偽値を返す関数)を満たす配列の
要素が只1つ
の場合、此の要素
を返す。
此の様な要素が無いか、2つ以上の場合、
- 3つ目の引数の値として
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
が渡された場合、エラーが投げられる。 然し、関数の実行がエラー無しで終了した場合、TypeScriptは、返ってきた値がnull
ではなく、ジェネリック引数で指定された (此の場合は常に暗黙的)型であると 見做す。 - 3つ目の引数が渡されなかった場合、
null
が返される。 但し、返された値を、ジェネリック引数で指定された型の値 として利用するには、非null確認が必要に成る。
例
const sample: Array<string> = [ "Saint Paul", "Santa Barbara", "St. Louis", "Santa Monica" ];
「Santa」
から始まり、
3件が「Sa」
から始まっているが、「St.」
から始まっているのは1件のみである。
const targetCityName: string | null = getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample, (arrayElement: string): boolean => arrayElement.startsWith("St.")
);
プレディケートに依ると「St.」から始まるものが必要である。 上記の例の場合、此の条件を満たすものが丁度1個有る為、 3つ目の引数の要素が返される。
然し、実行する時には配列の中身は、事前に知られていない。 此の様に「St.」から始まる要素が期待されていても実際に1個存在している訳では なく、そもそも存在している訳もない。 其れで、此の引数の組み合わせだと、nullが返される可能性が有る。
console.log(targetCityName.length);
TypeScriptはエラーTS18047
(「'targetCityName' is possibly 'null'」)を投げる。
length
プロパティは文字列(と配列)には存在しているが、
targetCityName
はnull
に成っている可能性が有るのが
原因である。
length
を含め、文字列のプロパティや
メソッドを呼び出す前には、targetCityName
は
非null
であることを保証
しなくてはならない。
if (targetCityName !== null) {}
の様に、条件文を使う事が一つの方法である。
此の場合、条件文の中にある値は
非null
であると、TypeScriptは見做す。
他の解決方法も有るが、TypeScriptが出来ると発言しているエンジニアが絶対に
使っては成らない表現は、targetCityName!.length
である。
コードの品質を大きく損なう為である。
普通、此の様な機能を使っているエンジニアは、any
型も幅広く使い、
其の他のTypeScriptを利用する事で得られる利点を無くしている、
有害な機能を使用している事が多い。
console.log(
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample, (arrayElement: string): boolean => arrayElement.startsWith("Santa")
)
);
プレディケートを満たす要素が2個なので、 nullが返される。 関数名を和訳すれば御分かりだと思うが、せっかく説明書を読んでくださっているので、翻訳では「丁度 1つの~要素」を含めると繰り返しておこう。
プレディケートを満たす要素が1個のみで、
其れ以外に成る事は無いと言い切れる場合、
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
を
3つ目の引数として渡す事が出来る。
結果として、TypeScriptは非null確認を求めないが、期待に反して
プレディケートを満たす要素の数が丁度1個では なくなった場合、
UnexpectedEventError
が投げられる(思われるより此れの可能性が高い)。
const matching: string = getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample,
(arrayElement: string): boolean => arrayElement.startsWith("Santa"),
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
);
matching
の型としてstring | null
では
なく、string
を指定出来る。
プレディケートを満たす要素が無かった場合か、此の様な要素が
2個以上の場合、null
が返されるのではなく、UnexpectedEventError
が投げられる。
勿論、此の例外をtry/catch
で処理出来るが、一般的には
上に考察された非null確認の使い方に比べて、特に利点は無い。
ネイティブメソッドとの比較
下記ネイティブメソッドは
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
関数
より良くも無いが、悪くも無い。
何を使えば良いかは、下記の状況に於ける望ましい振る舞いに依って事と成る。
- プレディケートを満たしている配列要素が1つも 無い
- プレディケートを満たしている配列要素が 2つ以上有る
Array.prototype.find
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
との 共通点は、両方がプレディケートを満たしている 要素を探している事。- プレディケートを満たしている要素が無い場合、
Array.prototype.find
はundefined
を返すが、getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
は 第3引数に依りnull
を返すか、エラーを投げる。 但しエラーを投げる事が選ばれた場合、TypeScriptは非null確認を求めない。Array.prototype.find
の場合は、非undefined確認が必要に成る為にgetArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
を使いたく成る事が多い。 - プレディケートを満たしている要素が#2つ以上
の場合、
Array.prototype.find
は1つ目を返し、残っているものを 無視する。 此れに対して、getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
は プレディケートを満たしている要素を見つけてから、同じプレディケート を満たしている他の要素が無いかどうかを確認し、有った場合はどの要素も返さない。 配列要素を単に取得する事の他に、此の配列要素は他の要素と違う特性が有るか どうか(例えば唯一の識別子)、確認したい時に便利。
Array.prototype.filter
此のメソッドは、配列に在る特定の単一の 要素を取得する為ではなく、元の配列からの標本を取得する為にある。 此の様に、此の配列のメソッドが返していているのも 配列であり、即ちプレディケートを満たしている全ての 要素の配列である。
プレディケートを満たしている要素が無い場合、空の配列
が返される。
此の配列の何れの要素(1番目、つまり指数が
0個)にアクセスしても、undefined
が返される。
TypeScriptや、其の他の多数の静的型付けのプログラミング言語が此れについて
警告しない(例えば、Array<string>
又は
string[]
は、文字通り「数が無限の文字列の
要素の配列」を意味しているが、事実上どの配列も
有限で、空に成っている事も有る)。
「IntelliJ IDEA」ファミリー統合開発環境に於ける高速入力
「IntelliJ IDEA」ファミリー の統合開発環境のLive templates 機能利用の恩恵に依り、関数呼び出し表現等の入力速度が向上する。 YDEEのライブテンプレートを取得するには、当ライブラリの正式プラグイン を導入する必要が有る。
Live Templateの利用手順
ライブテンプレートを使った事が無い場合でも、充実した内容の手順書が下記にある為、心配は無用である。 ライブテンプレートに慣れてしまえば、(キーボードのショートカット利用と同じ様な習慣)僅か数秒程度で下記の操作を行える。
- 配列を含む変数の名前か、配列表現をクリップボードにコピーして下さい。
結合開発環境が、
1つ目の
引数の位置に正しい値が入れられる様に、 getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne関数 のLive templateを入力し始める前に、予め此れをクリップボードにコピーする習慣を作って下さい。 - getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne関数の
名前を入力し始めて下さい。
オートコンプリートに依り、下記の2件が表示されます。
- アルファベット文字が丸に囲まれているアイコン:関数の名前のオートコンプリートで、結合開発環境の 規定の機能である。 Enterを押すと、関数の名前が入力され、必要に応じてインポートの 宣言も追加される。 悪くはないが、更に自動化が可能である。
- 版のアイコン:我々が必要なテンプレート。 Enterを一度押すと、テンプレートのコードが入力され、1つ目の引数 の位置はクリップボードの内容で埋められ、カーソルで選択できる。 此の説明に従えば、貼り付けされた値は不要なので、1つ目の引数の編集を終了するには もう一度Enterを押下する。
- プレディケート(アロー関数である)の引数の名前を入力して下さい。 此の引数は配列の要素だが、「element」より幅が狭い名前を付ける事を 御勧めします。 入力が終わったら、Tabを押して下さい。 今回、不要なオートコンプリートが邪魔に成る場合、先にEscを押してください。
- プレディケートの引数の名前を入力し
Enter
を押して下さい。 - 余計なコードを削除しておきましょう。