From 1eb4331a0236bd2c914d6d202ab0d1057e967d2e Mon Sep 17 00:00:00 2001 From: WofWca Date: Tue, 14 Mar 2023 11:07:56 +0400 Subject: [PATCH] WIP: proper types for `objectToCamelCase` --- package.json | 1 + pnpm-lock.yaml | 6 ++++++ src/helpers/case.ts | 46 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b39a3e237f..4de2eace80 100644 --- a/package.json +++ b/package.json @@ -124,6 +124,7 @@ "eslint-plugin-vue": "9.9.0", "happy-dom": "8.9.0", "histoire": "0.15.8", + "literal-case": "^1.0.0", "netlify-cli": "13.1.2", "postcss": "8.4.21", "postcss-easing-gradients": "3.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 632d9784e0..153e25ae0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,6 +64,7 @@ specifiers: histoire: 0.15.8 is-touch-device: 1.0.1 klona: 2.0.6 + literal-case: ^1.0.0 lodash.debounce: 4.0.8 marked: 4.2.12 netlify-cli: 13.1.2 @@ -177,6 +178,7 @@ devDependencies: eslint-plugin-vue: 9.9.0_eslint@8.36.0 happy-dom: 8.9.0 histoire: 0.15.8_mbllq5flobsmlktljlyrk4fpme + literal-case: 1.0.0 netlify-cli: 13.1.2_@types+node@18.15.1 postcss: 8.4.21 postcss-easing-gradients: 3.0.1 @@ -10278,6 +10280,10 @@ packages: wrap-ansi: 7.0.0 dev: true + /literal-case/1.0.0: + resolution: {integrity: sha512-uJJFKXDMip5SraJINCO0as7guJkbMR1iVSkTpYIXaD6eaFuggskZyKcuAWYQJyJYoD39MWiAIPxTf/TystKq/g==} + dev: true + /local-pkg/0.4.2: resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} engines: {node: '>=14'} diff --git a/src/helpers/case.ts b/src/helpers/case.ts index 81933d3610..78b046c975 100644 --- a/src/helpers/case.ts +++ b/src/helpers/case.ts @@ -1,10 +1,50 @@ -import {camelCase} from 'camel-case' -import {snakeCase} from 'snake-case' +import {camelCase as camelCaseUntyped} from 'camel-case' +import {snakeCase as snakeCaseUntyped} from 'snake-case' +import type { + camelCase as camelCaseTyped, + snakeCase as snakeCaseTyped, + CamelCase, + SnakeCase, +} from 'literal-case' + +const camelCase = camelCaseUntyped as typeof camelCaseTyped +const snakeCase = snakeCaseUntyped as typeof snakeCaseTyped + +// type ObjectToCamelCase = { +// [P in keyof T as (P extends string +// ? CamelCase

+// : P +// )]: T[P] extends (Record | unknown[]) +// ? ObjectToCamelCase +// : T[P] +// } +type NestedObjectsToCamelCase< + // T extends (Record | unknown[]) + T +> = T extends unknown[] + ? { + // Change array elements while keeping prototype properties the same. + [P in keyof T]: P extends number + ? NestedObjectsToCamelCase + : T[P] + } + // TODO what about class instances here? Methods would also get transformed. Is it right? + // : T extends Record + : T extends Record + ? { + [P in keyof T as (P extends string + ? CamelCase

+ : P + )]: NestedObjectsToCamelCase + } + : T /** * Transforms field names to camel case. */ -export function objectToCamelCase(object: Record) { +export function objectToCamelCase>( + object: T, +): NestedObjectsToCamelCase { // When calling recursively, this can be called without being and object or array in which case we just return the value if (typeof object !== 'object') {