こんにちは(๑╹ω╹๑ )
↓ つい先日投稿した記事を多くの方に読んで頂けてとても嬉しいです(語彙力.....
「Vercel + freenom + Getform.io」構成で「爆速 + 管理費完全無料」のポートフォリオをGatsbyJSで作ったら幸福度が高まった話
今日はJavascript(主にTypeScriptスタックの無い環境)で型のバリデーションをする機構の実装について紹介します👼
少し特殊な書き方をしますが、可変メソッドを多用する立ち回りで実装できます😄
可変メソッドとは
- メソッド名からメソッドを評価する
ことです。
PHPでは、
- 可変変数
- 可変関数
- 可変クラス
等できるかと思いますが、
それに近しい立ち回りです🙆♂️
以前、PHPの言語仕様の理解を深める特殊な立ち回りでも紹介した下記のPHPコードを見てください👨💻
$orange_price = "300円";
$var = "orange_price";
echo $$var; //300円
↑のような立ち回りをJavascriptのメソッドでもしよう💪ということです!
実は簡単🤔 JavaScriptの可変メソッド😊
まず↓を眺めましょう🙌
console.log("Hoge")
言語仕様まで追っている訳ではありませんが、
console
というクラスのlog
という@staticmethod
にHoge
というString型の値を渡して、
console.log("Hoge")
を評価させていますよね🐥
console
はオブジェクトだということも
分かるので
ということは、、、、!
console['log']("Hoge");
も同様に評価されるということです😲
よって、log
というString型
の値を定義しておくと、、、、
const Var = 'log';
console[Var]("Hoge");
のように可変メソッド
で立ち回る事ができます🧐
可変メソッドをコールするメソッドを書いてみる
PHPのcall_user_func_arrayをJavascriptで実装してみます。
※メソッドのみ
↓書いてみました!
class Hoge {
displaymMssage( mssage ){
console.log(mssage);
}
callUserMethodArray(
methodName,
var
){
this[methodName](var);
}
}
const hoge = new Hoge;
hoge.callUserMethodArray(
'displaymMssage',
'Hoge!!!'
);
// => Hoge!!!
もちろん許容する引数の数は、
必ずしも1つでは無いので、
引数が複数である場合も考慮して書いてみました🥺
class Hoge {
displaymMssage( mssage1, mssage2 ){
console.log(mssage1);
console.log(mssage2);
}
callUserMethodArray( methodName, vars ){
this[methodName].apply( this, vars );
}
}
const hoge = new Hoge;
hoge.callUserMethodArray(
'displaymMssage',
[ 'Hoge!!!', 'Foo!!!' ]
);
// => Hoge!!!
// => Foo!!!
apply
で立ち回ると出来ますね!
これに可変プロパティを用いることも簡単です
class Hoge {
constructor(){
this.mssage1 = "Hoge!!!";
this.mssage2 = "Foo!!!";
}
displaymMssage( var1, var2 ){
console.log( this[var1] );
console.log( this[var2] );
}
callUserMethodArray( methodName, vars ){
this[methodName].apply( this, vars );
}
}
const hoge = new Hoge;
hoge.callUserMethodArray(
'displaymMssage',
[ 'mssage1', 'mssage2' ]
);
// => Hoge!!!
// => Foo!!!
動的に型のバリデーションを行う
動的に可変メソッドを用いて立ち回ると、
Non TypeScriptスタックでも簡単にバリデーションチェックを行う機構を実装できます!
class Hoge {
constructor(){
this.validationRules = {
displaymMssage: [
"string",
"boolean",
"number",
]
};
}
displaymMssage( mssage1, mssage2, mssage3 ){
console.log(mssage1);
console.log(mssage2);
console.log(mssage3);
}
validationArguments( methodName, vars ){
const rules = this.validationRules[methodName];
return rules.map(
( rule, key ) => {
return (
typeof vars[key] === rule
? null
: rule
);
}
).filter(Boolean);
}
callUserMethodArray( methodName, vars ){
const validationResult = this.validationArguments( methodName, vars );
if(validationResult.length > 0){
const errorTypes = validationResult.join(" and ");
return `Failed to validate the argument. Pass the correct ${errorTypes}.`;
}
this[methodName].apply( this, vars );
}
}
const hoge = new Hoge;
const result = hoge.callUserMethodArray(
'displaymMssage',
[ 'Hoge!!!', 10, true ]
);
console.log(result);
// => Failed to validate the argument. Pass the correct boolean and number.
↑です!
簡単に解説をします🤗
this.validationRules = {
displaymMssage: [
"string",
"boolean",
"number",
]
};
Hoge
クラスのconstructor
で定義をした↑は、
displaymMssage
というメソッドで許可する型
を
引数順に文字列で定義しています。
※ サンプルコード内ではstring型、number型、boolean型の順番で実行させようとしています。
validationArguments
メソッドでは、
const rules = this.validationRules[methodName];
↑で該当のルールをrules
で定義しています。
return rules.map(
( rule, key ) => {
return (
typeof vars[key] === rule
? null
: rule
);
}
).filter(Boolean);
↑では、事前に定義した型とdisplaymMssage
メソッドを実行するために渡された引数の型が
同一であるか確認しています。
その後、想定していない型であれば、
型名をstring型(rule
)で返却します。
map
によって返却された配列を、
.filter(Boolean);
でnull
を除去しています。
ここでnull
を除去出来るのは、
Boolean(null)
がfalse
であるためです。
そして、callUserMethodArray
メソッド内では、
バリデーションエラーがあった場合に、
エラー分をreturn
しています。
.filter(Boolean);
でnull
を除去していたので、
バリデーションエラーがあるのはvalidationArguments
から返却された配列が空で無い時です。
これらの処理により、型のバリデーションに失敗した場合は想定のメソッドを評価させること無く、
例外エラーを差し込むことが出来ます🤗
[ 'Hoge!!!', true, 10 ]
を引数とすると、
// => Hoge!!!
// => true
// => 10
となって期待する処理の結果を得ることが出来ます。
まとめ
型のバリデーションを行うために、
ワンクッションメソッドを挟むことになり少し手間です。
どうしても、
「Non TypeScriptでないといけない😭
でも型のバリデーションはきちんと行いたい😭😭」
という場合には活用できそうですね😄