const hoge : string = 'hoge';
if(hoge === 'fuga' || hoge === '(「・ω・)「がおー'){
return true;
}
else{
return false;
}
みたいに、
比較対象(今回は
String
)がいずれかの候補と同じものであればtrue
そうでなければfalse
を返す
こういうケース、そんなに多くないけど実際書くと面倒くさいよね
(この例は最悪なもので、普通なら候補を Array
に突っ込んで map
で順に比較みたいなのが多いと勝手に思う)
本記事では、このめんどくさいを解決する拡張メソッドを深夜テンションで書いてみた話をお送りいたします。
メソッド命名から入ってみる
私は残念なことに英語を雰囲気で読むくらいしかできないので命名はGoogle先生に頼ることにしました
ながったらしい。 結局少し考えて.anyIn()
で行くことで決めた。ソッチのほうが自然そう。
メソッドの仕様
'hoge'.anyIn('fuga', 'hoge'); // => true
'fuga'.anyIn('f') // => false
だいたいこんな感じの記述デザインにしてみた。可変長引数を使えば実装も難しくはなさげ
実装
こちらのサイトを参考にさせていただきました。
https://kakkoyakakko2.hatenablog.com/entry/2018/06/12/003000
// これないとエラーが出る
export {};
declare global {
interface String {
/**
* 引数のStringと呼び出し元のStringをORで比較して
* どれかと等しければ `true` でなければ `false`
* @param word string 1つ目(**require param**)
* @param args string 2つ目以降(option)
*/
anyIn(word : string, ...args: Array<string>): boolean;
}
}
// ここはArrow Functionにしてはいけない(後述)
String.prototype['anyIn'] = function(word: string, ...args: Array<string>) : boolean{
if(this === word){
return true;
}
else{
// ここからはもうちょっと楽にかけたかも
let result : boolean = false;
args.forEach((char) => {
if(this === char){
result = true;
}
});
return result;
}
};
...
は可変長引数の宣言をしているだけ。使用する際2つ目以降の引数が順番にArray
に突っ込まれる。
あとはJSでの拡張定義に型の注釈が増えたくらい。
あとは使うタイミングで import
してやればString
にぶら下がるメソッドとして使用可能。
import './string_extention';
console.log('hoge'.anyIn('ho', 'hoge')); // => true
ArrowFunctionについて気をつけること
ほぼほぼのFunction定義は() =>
で書けるが、今回のケースでは呼び出し元をthisで拾えることが前提となる。('hoge'.anyIn()
の中で'hoge'
を拾えるようにする)
ここで気をつけないといけないのが、Arrow Functionにおけるthis
の束縛について。
MDNのドキュメントには以下のように記述されている
アロー関数式は、より短く記述できる、通常の function 式の代替構文です。また、this, arguments, super, new.target を束縛しません。
どういうこっちゃ?🤔
まあ言いたいことはぶっちゃけmejileben氏の記事で解説されているので要約すると
-
function()
ではthis
を実行する段階で確定している。 - それに対し
() =>
のthis
は宣言の段階で確定している。 - そのためレシーバを拾う必要のあるメソッドは
function()
で定義する - 今回の場合
'hoge'.anyIn()
で書きたいのでArrow Functionは使えない
という感じ
まとめ
- 意外と簡単に拡張メソッドを作れる あと書いていて気持ちいい命名になったかも
- Arrow Functionは楽に書けるし視認性も上がるのでほぼ置き換えても良い。
- 今回のように例外となるケースもあることは理解しておくこと。