Is there a more efficient approach to creating a Typescript XML parser that does not rely on PropTypes?

I'm currently designing the architecture for a web application that will require the consumption of SOAP APIs in hundreds, if not thousands, of instances. These implementations will be developed by 200-300 different developers over a span of several years. Understanding the scope of this project and the number of individuals involved, my aim is to streamline the interaction with this SOAP API through Typescript to minimize complexity.

My goal is to avoid requiring each developer to manually convert strings into their respective types every time a request is made to the API. To achieve this, I am working on handling the conversion process for them. However, due to Typescript's limitations in reflection capability, this task has proven to be somewhat challenging. I have resorted to using a PropTypes approach.

Unfortunately, this approach involves duplicating the structure definition, as it needs to be available in both the TS type (compile-time/type space) and the PropTypes package (run-time/value space). While omitting some implementation details for brevity, I have devised a solution utilizing the prop-types package as seen below:

/* code snippet */

Despite my efforts, I am concerned about the potential for divergence between the two definitions of the User type. As a newcomer to Typescript, I am curious if there are more conventional or intuitive ways within Typescript to tackle this challenge that I might have overlooked?

Answer №1

Perhaps this solution could be beneficial for you:

type RenameProp<
  T extends string, 
  S extends string
> = T extends `${S}${infer Substring}` ? Substring : never

type TransformToType<T, S extends string> = { 
  [K in keyof T as K extends string ? RenameProp<K, S> : never]: T[K] 
}

type User = TransformToType<typeof propTypes, 'User.'>

/*
    type User = {
        'UserId': number
        'UserName': string
        'UserType': number
    }
*/

We can utilize the object propTypes to generate another type named User. For T, we utilize the typeof propTypes and for S, a substring that needs to be removed from the beginning of the property names, in this case 'User.'.

The issue might arise from the prop-types package. It may not be clear whether typeof PropTypes.number will resolve to number.


Update:

I just noticed that PropTypes are nested within Requireable. We can handle that as well:

type RenameProp<
  T extends string, 
  S extends string
> = T extends `${S}${infer Substring}` ? Substring : never

type ExtractRequireable<T> = T extends Requireable<infer S> ? S : never

type TransformToType<T, S extends string> = { 
  [K in keyof T as K extends string ? RenameProp<K, S> : never]: ExtractRequireable<T[K]> 
}

type User = TransformToType<typeof propTypes, 'User.'>

Now, the type of User aligns exactly with the specifications mentioned in your initial query.

Sandbox

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

Angular virtual scrolling not populating the list with data

I have encountered a challenge while trying to implement infinite virtual scroll on an Angular 7 project with a GraphQL backend from Hasura. I am puzzled by the fact that the new data is not being added and there are multiple API requests being made when ...

Controlling the Output in Typescript without Restricting the Input

I am interested in passing a function as a parameter, allowing the function to have any number of parameters but restricting the return type to boolean. For example, a function Car(driver: Function) could be defined where driver can be ()=>boolean or ( ...

What exactly is the purpose of the colon in JavaScript's import statement?

Looking at the following example. import { QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database' I am puzzled by the use of colons and I am unsure about where the imported files are being referenced from. ...

Nextjs 14 experiences full page loading due to the presence of multiple root layouts

The issue I'm facing involves a full page load when navigating between two root layout pages In my Next.js application (NextJS 14), I have created two root layouts. However, when moving from the first layout to the second layout, it triggers a comple ...

Accepting undefined in rest parameter of typescript

I'm struggling with an exercise involving Function parameters: The maximum function below has the wrong type. To allow undefined in the rest arguments, you need to update the type of the rest parameter. Fortunately, you don't have to change the ...

Can you explain the functionality of the statement a:bc = 9 in JavaScript?

Currently in my JavaScript code, I have the equation a:bc = 9. Upon executing `console.log(bc)`, it correctly shows 9. However, if I try to `console.log(a)`, I receive an error stating that "a" is not defined. Can someone provide clarification on what i ...

Access data inside nested objects with specified data type

Imagine the code snippet below: type Parent = { children: Child[] } type Child = { label: string } const parent: Parent = { children: [ { label: 'label1' }, { label: 'label2' } ] } How can I use generics to ...

Working with Vue class-based components in TypeScript and setting props

Currently tackling a typescript-related issue within a class-based component and seeking guidance on a persistent error. Below is the code snippet for my component: <template> <b-message :type="statusToBuefyClass"> <p>PLACEHOLDER& ...

"Exploring the New Feature of Angular 17: Named Router Outlets Implemented

One issue I am facing with my application is the rendering of different pages based on whether a user is logged in or not. The generic pages like the landing or logout page should be displayed within the primary router-outlet when the user is not logged in ...

How to handle form-data in NestJS Guards?

I've been trying to access form-data in my NestJS Guards, but I'm experiencing some difficulties. Despite following the tutorial provided here, I am unable to see the request body for my form-data input within the Guard itself. However, once I ac ...

Using private members to create getter and setter in TypeScript

Recently, I developed a unique auto getter and setter in JavaScript which you can view here. However, I am currently unsure of how to implement this functionality in TypeScript. I am interested in creating an Object Oriented version of this feature if it ...

Exploring Angular: Looping through an Array of Objects

How can I extract and display values from a JSON object in a loop without using the keyValue pipe? Specifically, I am trying to access the "student2" data and display the name associated with it. Any suggestions on how to achieve this? Thank you for any h ...

Is Drizzle ORM able to handle decimal values in MySQL as strings?

The data structure: export const myTable = mysqlTable( "MyTable", { id: varchar("id", { length: 191 }).notNull(), value: decimal("value", { precision: 7, scale: 4 }).notNull(), createdAt: datetime("created ...

Leverage Webpack to bundle ES Modules with TypeScript module aliases

Hello there, I recently created an npm module using Typescript and ES-modules. Inside the /source folder, you can find my tsconfig.json file which includes a path alias. { "compilerOptions": { "moduleResolution": "Node ...

Angular button press

Recently, I started learning Angular and came across a challenge that I need help with. Here is the scenario: <button *ngIf="entryControlEnabled && !gateOpen" class="bottomButton red" (click)="openGate()">Open</button> <button *ngIf ...

ngx-datatable detail row failing to expand properly

I am striving to develop an ngx-datatable component that can be utilized universally for consistent styling and functionality. Although most features are working correctly, I'm struggling to understand why the details row isn't expanding as expe ...

Issue with the declaration of custom types in Typescript

I've created a type declaration for r-dom as shown below: /// <reference types="react" /> declare module 'r-dom' { interface IRDOMFacade extends React.ReactDOM { (component: React.Component<any, any>, properties?: ...

What is the best way to determine the type of a key within an array of objects

Suppose I have the following code snippet: type PageInfo = { title: string key: string } const PAGES: PageInfo[] = [ { key: 'trip_itinerary', title: "Trip Itinerary", }, { key: 'trip_det ...

Subscriber fails to receive updates from Behavior subject after calling .next(value)

I am facing an issue where a Behavior Subject does not update a subscriber upon the .next(value) call. Being new to typescript, I believe I might be overlooking something small. The implementation seems correct based on what I have researched. Although t ...

Utilize the gsap ScrollTrigger in conjunction with React's useRef() and Typescript, encountering issues with type mism

Recently, I've been trying to add some animation to a simple React Component using the GreenSock ScrollTrigger plugin. However, I ran into an issue due to types mismatch in my Typescript project. Here's a snippet of the code: import React, {useRe ...