🕵️
Yupで配列内のオブジェクトのプロパティがユニークであることを検証する方法
バリデーション用ライブラリ Yup で、配列内のオブジェクトのプロパティが重複していないことを検証する方法。
READMEには重複チェックについて書かれていなかったのでまとめておく。
例えば、url
と caption
を持つオブジェクトの配列で url
がユニークであることを検証する場合、こんな感じに書ける。
import * as yup from "yup";
const objectSchema = yup.object().shape({
url: yup.string().url(),
caption: yup.string(),
})
yup
.array()
.of(objectSchema)
.test("unique", "${path} must be unique", (list) => {
return !list || list.length === new Set(list.map((i) => i.url)).size;
});
Arrayの要素数と対象プロパティのSetの要素数を比較する。
汎用的にする場合は yup.addMethod で独自のメソッドを追加できる。
TypeScriptでの実装例。
import * as yup from "yup";
import { Message } from "yup/lib/types";
declare module "yup" {
interface ArraySchema<T> {
unique(mapper?: (a: T) => any, message?: Message): ArraySchema<T>;
}
}
yup.addMethod(
yup.array,
"unique",
function (mapper = (a: any) => a, message = "${path} must be unique") {
return this.test("unique", message, (list) => {
return !list || list.length === new Set(list.map(mapper)).size;
});
}
);
これで追加した unique
メソッドが使えるようになる。
yup.array().of(objectSchema).unique((i) => i["url"]);
オブジェクトじゃなくても使用できる。
配列内の文字列がユニークであることを検証する場合はこんな感じに書ける。
yup.array().of(yup.string()).unique();
このIssue が参考になりました。
Discussion