Transform the `PascalCase` format into `strictCamelCase` in TypeScript type conversion

By utilizing the built-in Uncapitalize<S> function, you can easily convert a string like FooBar to fooBar:

const fooBar: Uncapitalize<'FooBar'> = 'fooBar';

However, this method proves inadequate when dealing with class names that adhere to the HTML5 convention, such as XMLHttpRequest:

const xmlHttpRequest: Uncapitalize<'XMLHttpRequest'> = 'xMLHttpRequest';

Specifically, a type is required that can:

  1. Convert instances of PascalCase containing multiple connected UPPER_CASE letters forming an acronym, into a strictCamelCase string type that makes the acronyms lowercase,
  2. Avoiding multiple capital letter clusters.

For instance:

  • XMLHttpRequest -> xmlHttpRequest
  • HTMLAnchorElement -> htmlAnchorElement
  • FOOBaAAr -> foobaaAr

Since this will be used for code validation rather than transforming user input, aesthetics are not a priority, as it becomes the responsibility of the developer to rectify their naming conventions (:

It is known that the new template literal types in TypeScript, particularly their inference features, can be employed for this purpose. However, the provided examples only demonstrate one-sided inference, like ${infer Foo}bar, and utilizing multiple inference types often results in the last one being greedy, such as

${infer FirstChar}${infer Rest}bar
.

Answer №1

To solve the issue of greediness, you can employ recursion at the type level.

type StrictCase<S extends string> =
  S extends `${
    infer P1 extends Uppercase<string>
  }${
    infer P2 extends Uppercase<string>
  }${
    infer P3
  }`
    ? `${Lowercase<P1>}${StrictCase<`${P2}${P3}`>}`
    : S extends `${infer P1}${infer P2}`
    ? P2 extends ''
      ? Lowercase<P1>
      : `${P1}${StrictCase<P2>}`
    : S;

type StrictPascalCase<S extends string> = Capitalize<StrictCase<S>>
type StrictCamelCase<S extends string> = Uncapitalize<StrictCase<S>>;

When dealing with the StrictCase<S> type:

  1. If there are two adjacent uppercase letters -> FOOBar
    1. These are the uppercase letters causing issues
      Convert the first character to lowercase, then apply StrictCase<S> to the remaining characters. -> f
      StrictCamelCaseImpl<'OOBar'>
  2. If only one letter remains -> r
    1. Convert to lowercase and return. -> r
  3. If there are at least two letters -> Bar
    1. These can be in any combination of cases
      Preserve the first character, then continue with StrictCase<S> on the rest. -> BStrictCamelCaseImpl<'ar'>
  4. Else -> ar
    1. Return as is -> ar

After these transformations, to convert to either camelCase or PascalCase, simply apply Capitalize<S> or Uncapitalize<S> respectively, which alters the first letter to uppercase or lowercase.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Describing the implementation of UNO out parameters within definitions

The UNO API offers support for inout and out parameters. In this scenario, a variable is passed into a function, the function modifies the variable, and the updated value of the variable can be accessed outside the function. Javascript lacks native suppor ...

The export 'ChartObject' is not available in highcharts

Trying to integrate highcharts into my Angular 4 project has been a bit challenging as I keep encountering the following error: highcharts has no exported member 'ChartObject' I have experimented with different options such as angular-highchart ...

Troubleshooting Node.js import module errors

I have just discovered two files that I created using the TS language specification manual (on page 111). The first file, called geometry.ts, contains the following code: export interface Point { x: number; y: number }; export function point(x: number, y ...

Error message: Unable to retrieve `__WEBPACK_DEFAULT_EXPORT__` before initializing Firebase Admin in a nx and nextjs application

My current project involves a Typescript Nx + Next.js App integrated with Firebase (including Firebase Admin). In this codebase, I have defined a firebase admin util as shown below - // File ./utils/FirebaseAdmin.ts // import checkConfig from './check ...

How can Angular JS handle multiple validators being triggered at once?

Hey there, I'm currently working with validators in my Angular form setup. Here's a snippet of how it looks - I utilize Validators.compose to combine custom validators. The errors from these validators are then displayed on the HTML component. My ...

Angular, manipulating components through class references instead of creating or destroying them

I am exploring ways to move an angular component, and I understand that it can be achieved through construction and destruction. For example, you can refer to this link: https://stackblitz.com/edit/angular-t3rxb3?file=src%2Fapp%2Fapp.component.html Howeve ...

Focusing in on a particular category of items based on a specific characteristic

I can't seem to understand why typescript has an issue with the code below. The errors from the compiler are detailed in the comments within the code. const FOO = Symbol(); function bar<T>(param: T) { if (param !== null && typeof para ...

Discovering the steps to showcase _app.tsx within next.js 13 through module federation

I am faced with a situation where I have two Next.js 13 projects: Homepage and Admin Panel. My goal is to showcase the entire Admin Panel (specifically _app.tsx) and embed it within Homepage. To achieve this, I have set up both projects utilizing @module-f ...

Turning an array of strings into a multidimensional array

I have a JavaScript string array that I need to convert into a multidimensional array: const names = [ "local://john/doe/blog", "local://jane/smith/portfolio", "as://alexander/wong/resume" ]; The desired output sh ...

Is there a way to assign API data as inner HTML using Lit?

Need help setting inner html of html elements with a get request Any suggestions on how to achieve this? import { LitElement, html, css } from "lit"; import { customElement } from "lit/decorators.js"; import axios from "axios" ...

Combine Two Values within Model for Dropdown Menu

I am currently facing a situation where I have a select box that displays a list of users fetched from the backend. The select box is currently linked to the name property of my ng model. However, each user object in the list also contains an email proper ...

Issues with loading AddMarker on initial launch in Ionic 2

Can someone help me figure out what's causing the issue in my code? When I try to load a google map in my ionic 2 app, the marker doesn't show up the first time. It only appears when I reload the map for the second time or later. I also need ass ...

Creating a function that utilizes a default argument derived from a separate argument

Consider this JavaScript function: function foo({ a, b, c = a + b }) { return c * 2; } When attempting to add type annotations in TypeScript like so: function foo({ a, b, c = a + b }: { a?: number, b?: number, c: number }): number { return c * 2; } ...

An error has occurred: TypeError - The class constructor $b802fbb11c9bd2dc$export$2e2bcd8739ae039 must be called with 'new'

I am attempting to integrate emoji-mart into my application, but I keep encountering a persistent error. Here is the snippet of code causing the issue: import data from '@emoji-mart/data' import { Picker } from 'emoji-mart' {showEmoji ...

Inserting information into an array: Access the final index consistently with TypeScript

I am interested in dynamically creating a table by allocating it, with the variable nbrBoules: boules:Boule :[] boule:Boule; Boule{id,poids} Method(){ for (var _i = 0; _i < this.nbrBoules; _i++) { this.boule.id = _i; alert(_i); this ...

What is the process for recording information using a static method in TypeScript within a class?

For my school project, I'm struggling to retrieve the names from a class using a method. One class creates monsters and another extends it. abstract class genMonster { constructor( public id: string, public name: string, public weaknesse ...

Navigating conflicts between packages that utilize TypeScript can be tricky. Here are some strategies for handling these situations

I recently encountered an issue while following a tutorial to create a WhatsApp clone using Meteor. The tutorial link is here The problem arose at the end of section 8 when I executed the $meteor reset command as directed. However, upon running the $ n ...

Leverage the exported data from Highcharts Editor to create a fresh React chart

I am currently working on implementing the following workflow Create a chart using the Highcharts Editor tool Export the JSON object from the Editor that represents the chart Utilize the exported JSON to render a new chart After creating a chart through ...

Unable to utilize React Icons component as an object value in typescript

Currently, as I develop my personal website using typescript and react, I am faced with an issue in the footer section. I have an array of objects with url and icon properties that I map through to display different icons on each iteration. Initially, this ...

Getting pictures dynamically from the backend with unspecified file types

Greetings to my fellow Stackoverflow-Users, Lately, I was tasked with the requirement of loading images dynamically from the backend into my application. Up until now, it was always assumed that we would only be dealing with SVG images since there was no ...