はじめに
API開発を進めていく中で、クラスオブジェクトの定義の中になにやら@Expose()
という呪文が書いていたので調べてみることにしました。
また、過去にはclass-transformerの概要についても書いてみました。
plainToClass()関数
まず、(プレーンオブジェクトを要素とする)連想配列usersと独自に定義したUserクラスがあるとします。
import { plainToClass } from "class-transformer";
const users = [
{
id: 1,
firstName: "Johny",
lastName: "Cage",
age: 27,
},
{
id: 2,
firstName: "Ismoil",
lastName: "Somoni",
age: 50,
},
{
id: 3,
firstName: "Luke",
lastName: "Dacascos",
age: 12,
},
];
export class User {
id: number;
firstName: string;
lastName: string;
age: number;
getName() {
return this.firstName + " " + this.lastName;
}
isAdult() {
return this.age > 36 && this.age < 60;
}
}
const realUsers = plainToClass(User, users);
console.log(realUsers[0].age, realUsers[0].isAdult(), realUsers[0].getName());
// 27 false Johny Cage
連想配列usersを、User
クラスにTransformすることで当該クラスのプロパティだけでなく、メソッドまで活用できるようになります。
plainToClass()関数のデフォルトの挙動の問題
import { plainToClass } from 'class-transformer';
class User {
id: number;
firstName: string;
lastName: string;
}
const fromPlainUser = {
unknownProp: 'hello there',
firstName: 'Umed',
lastName: 'Khudoiberdiev',
};
console.log(plainToClass(User, fromPlainUser));
// User {
// unkownProp: 'hello there',
// firstName: 'Umed',
// lastName: 'Khudoiberdiev',
// }
しかしデフォルトでは、plainToClass()
関数はプレーンオブジェクトfromPlainUser
の全プロパティを踏襲してきてしまいます。User
クラスにないプロパティでも上書きしてしまい、また、User
クラスにはあったid
プロパティも消されてしまいました。
「型がある程度保証されたままでTransformをしたい」というのが、ここでの課題になります。
Expose()してtype-safeなインスタンス化をする
上記のデフォルトの挙動による問題を解決するために、プレーンオブジェクトの全プロパティを踏襲してしまうのではなく、Transformした後に不必要なプロパティを排除するために、excludeExtraneousValues
なるオプションをつけることができます。
import { Expose, plainToClass } from 'class-transformer';
class User {
@Expose() id: number;
@Expose() firstName: string;
@Expose() lastName: string;
}
const fromPlainUser = {
unkownProp: 'hello there',
firstName: 'Umed',
lastName: 'Khudoiberdiev',
};
console.log(plainToClass(User, fromPlainUser, { excludeExtraneousValues: true }));
// User {
// id: undefined,
// firstName: 'Umed',
// lastName: 'Khudoiberdiev'
// }
ここで、出力結果にほしいプロパティは、User
クラスを定義した際にあらかじめ@Expose()
を宣言しておく必要があります。
最後に
自分が日頃インターンの業務で触っているソースコードを見て知らなかったところを備忘録にしてみました。この学びを共有できれば幸甚です。
参考