やりたいこと
言葉で説明するのが難しい。
コンストラクタを値にもつオブジェクトを渡してその形に基づく戻り値を得たい。
例えばplainToClassに使うオブジェクトを一緒に渡してインスタンスを生成するみたいなことがしたい。
const instances = cstrToInstance(
{dog: Dog, owner: Owner},
{dog: {name: 'tarou'}, owner: {age: 20}}
);
console.log(instances); // { dog: Dog { name: 'tarou' }, owner: Owner { age: 20 } }
実装
import { ClassConstructor, plainToClass } from 'class-transformer';
function cstrToInstance<
S extends keyof T, // ※1
T extends { [key: string]: ClassConstructor<T[S]> }
>(
m: T,
params: { [key: string]: Record<string, unknown> } // ※2
): { [k in keyof T]: InstanceType<T[k]> } { // ※3
const r = {} as { [k in keyof T]: InstanceType<T[k]> };
for (const [key, type] of Object.entries(m)) {
const param = params[key] || {};
r[key as keyof T] = plainToClass(type, param) as InstanceType<T[keyof T]>;
}
return r;
}
※1 Sを宣言せず直接ClassConstructor<T[keyof T]>とやるとエラーになる。正直よくわかってない。
※2 要はただのオブジェクト
※3 k in keyof T と T[k]でキーに対応する型を一致させるのがポイント
動作
describe('cstrToInstance', () => {
it('型をplanToClassして返す', () => {
const instances = cstrToInstance(
{ dog: Dog, owner: Owner },
{
dog: { name: 'tarou' },
owner: { age: 20, dog: { name: 'jirou' } },
}
);
expect(instances.dog).toEqual(new Dog('tarou'));
expect(instances.owner).toEqual(new Owner(20, new Dog('jirou')));
});
});
