🥏
[Typescript]オブジェクトのキーを🐪→🐍に変換する[Javascript]
オブジェクトのキーをキャメルケースからスネークケースに変換するutil関数を作った後にts-case-convertで1行で解決出来ることを知った
TL;DL
インストール
npm install ts-case-convert
使い方
import { objectToSnake } from 'ts-case-convert';
objectToSnake(snakeCaseObject)
作成した関数
/** オブジェクトのキーをcamelCaseからsnake_caseに変換する */
export const convertKeysToSnakeCase = <T>(obj: T): T => {
if (typeof obj !== 'object' || !obj) return obj;
if (Array.isArray(obj)) {
return obj.map((value: T[keyof T]) =>
//objectがネストしている場合は再帰的にsnake_caseに変換する
typeof value === 'object' ? convertKeysToSnakeCase<T>(value as T) : value
) as T;
}
return Object.keys(obj).reduce((acc: T, key: string) => {
const snakeCaseKey = key.replace(
/[A-Z]/g,
(letter: string) => `_${letter.toLowerCase()}`
);
const value = obj[key as keyof T];
acc[snakeCaseKey as keyof T] = //objectがネストしている場合は再帰的にsnake_caseに変換する
typeof value === 'object' ? convertKeysToSnakeCase(value) : value;
return acc;
}, {} as T);
};
テスト
describe('テスト', () => {
test('convertKeysToSnakeCase', () => {
const input = {
firstName: 'John',
lastName: 'Doe',
age: 30,
address: {
streetAddress: '1234 Main St',
city: 'Anytown',
state: 'CA',
postalCode: '12345',
},
multiple: ['1', '2', { nestedMultiple: ['3', '4'] }],
};
const expectedOutput = {
first_name: 'John',
last_name: 'Doe',
age: 30,
address: {
street_address: '1234 Main St',
city: 'Anytown',
state: 'CA',
postal_code: '12345',
},
multiple: ['1', '2', { nested_multiple: ['3', '4'] }],
};
const actualOutput = convertKeysToSnakeCase(input);
expect(actualOutput).toEqual(expectedOutput);
expect({}).toEqual(convertKeysToSnakeCase({}));
});
});
Discussion
ぼくも少し試してみました。
推論結果がデモデータのパス式
result.abilities[0].slot
においてnumber|null
と推論してほしいところが、ts-case-convertライブラリの結果だとnumber|unknown[]
と推論されているようでした。想定しているユースケースとしては
WEB2DB
ないしはDB2WEB
のようなマッピングレイヤだと考えています。本件のようなワークアラウンドを達成したい場合を別のアプローチでトライしてみました。codesandboxだと正しく推論できないかもですが、手元では期待した型を得られているように見えました。
プロパティのキー名を変換したいデータの変換元と変換先の型をTypeHintするために型引数に渡して使う感じになります。
demo code.
簡単ですが、以上です。