参考にした記事
結果1(自作 冗長)
export const makeFlatObject = (
preobj: Record<string, unknown>,
parentProperty?: string
):Record<string, unknown> => {
const initialObject = {};
const makeObject: Record<string, unknown> = Object.entries(preobj).reduce(
(previousValue, currentValue, _index, _origin) => {
const result =
// 現在の値のvalueがobjectか?
typeof currentValue[1] === "object"
? // objectの場合、その中身は空ではないか?
Object.keys(currentValue[1] as Record<string, unknown>).length === 0
? // 空の場合はvalueに当たる部分が無いとkeyも消されてしまうのでvalueにundefinedを入れてkeyが消えないように保持する
{
...previousValue,
...{
[`${
parentProperty !== undefined
? parentProperty + "_" + currentValue[0]
: currentValue[0]
}`]: undefined,
},
}
: {
// からじゃ無い場合は中身のあるobjectなのでmakeFlatObjectに渡してネストした要素がフラットになるまで何回でも回す
...previousValue,
...makeFlatObject(
currentValue[1] as Record<string, unknown>,
currentValue[0]
),
}
: {
// そもそもobjectじゃない場合、純粋な値のはずなので{key:value}という形になるように整えて前回の値(作成しているflatなobject)に追加する
...previousValue,
...{
[`${
parentProperty !== undefined
? parentProperty + "_" + currentValue[0]
: currentValue[0]
}`]: currentValue[1],
},
};
return result;
},
// initialObject 初期値 ここに引数を用意しなければreduceに渡された配列の0番目になる 一番最初のpreviousValueに入る値
initialObject
);
return makeObject;
};
結果2(メンターから頂いた解答:掲載許可済み)
export const flattenObjWithGenerics = <T extends Record<string, unknown>>(
obj: T,
prefix = ''
): Record<string, unknown> => {
return Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object' && obj[k] !== null) {
Object.assign(
acc,
flattenObjWithGenerics(obj[k] as Record<string, unknown>, pre + k)
);
} else {
Object.assign(acc, { [pre + k]: obj[k] });
}
return acc;
}, {});
};
自分の場合Object.entriesを使用してkeyもvalueも取ってきていたがそもそもkeyだけでいい模様
コード量が多くなればなるだけ読み辛くなるのでもっとスマートに書けるようにならないとほんと・・・