Create TypeScript function to recursively generate generic keys, combining keys and excluding any objects

If you want to utilize filters in Prisma, it can be done as shown below:

prisma.user.findMany({
     where: {
         name: { contains: 'jeff' },
         city: {
             name: { contains: 'hol' },
             state: { 
                 acr: {
                     equals: 'vegas'
                 }
             }
         }
     }
})

To create the necessary object structure:

{
    name: '',
    city: {
        name: '',
        state: {
           acr: ''
        }
    }
}

The desired type output is:

type UserFilters = {
    name_contains?: string,
    name_equals?: string,
    city_name_contains?: string
    city_name_equals?: string
    city_state_acr_contains?: string
    city_state_acr_equals?: string
}

The code snippet that accomplishes this is:

type FilterR<Form> = Form extends object
    ? Partial<{
            [Key in string & keyof Form as `${Key}_${'contains' | 'equals'}`]: FilterR<Form[Key]>
      }>
    : Form

This results in the following structure:

Partial<{
    name_contains: "";
    name_equals: "";
    city_contains: Partial<{
        name_contains: "";
        name_equals: "";
        state_contains: Partial<{
            acr_contains: "";
            acr_equals: "";
        }>;
        state_equals: Partial<{
            acr_contains: "";
            acr_equals: "";
        }>;
    }>;
    city_equals: Partial<...>;
}>

Answer №1

Let's define a type that will generate a structure like this:

Record<originalKey, updatedKey>

The value of updatedKey will vary based on whether the property associated with the original key is an object or not. If it is an object, we append the original key to the beginning of the updated key using _ and recursively call the type for that property. Otherwise, we add 'contains' | 'equals' to the end of the original string. To achieve this structure, we require a union of all values, which can be achieved with the following type:

type ValueOf<T> = T[keyof T];

Let's create a type for the filter:

type Filter = 'contains' | 'equals';

Type that retrieves keys:

type FilterKeys<T> = ValueOf<{
  [K in keyof T & string]: T[K] extends object
    ? `${K}_${FilterKeys<T[K]>}`
    : `${K}_${Filter}`;
}>;

Testing:

// "name_contains" | "name_equals" | "city_name_contains" | "city_name_equals" | "city_state_acr_contains" | "city_state_acr_equals"
type A = FilterKeys<typeof obj>;

Looks promising!

All that remains is to utilize these keys in a mapped type:

type FilterR<T> = { [K in FilterKeys<T>]?: string };

// type A = {
//   name_contains?: string | undefined;
//   name_equals?: string | undefined;
//   city_name_contains?: string | undefined;
//   city_name_equals?: string | undefined;
//   city_state_acr_contains?: string | undefined;
//   city_state_acr_equals?: string | undefined;
// }
type A = FilterR<typeof obj>;

playground

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

My unique VSCode extension performs flawlessly during debugging, but encounters issues once installed

While debugging, my custom language extension for VSCode is functioning perfectly. However, once installed, the VSIX doesn't seem to include any TypeScript features. When I open the correct file extension type, it highlights everything and displays th ...

Converting types to "any" and encountering the error message "There are two distinct types with the same name, but they are not related."

I am encountering some challenges while trying to use an NPM module that I developed along with its Typescript typings in another application. To simplify the examples, I will omit properties that are not relevant to the issue at hand. Within my module&ap ...

What is the significance of utilizing generic types as values within a generic class?

Why is the compiler giving an error for the following code T' only refers to a type, but is being used as a value here: class Factory<T> { create(TCreator: (new () => T)): T { return new TCreator(); } test(json: string) ...

Issue with Discord.js (14.1) - Message Handling Unresponsive

After developing a sizable Discord Bot in Python, I decided to expand my skills and start learning JS. Despite thoroughly studying the documentation and comparing with my original Python Bot regarding intents, I am facing difficulties getting the message ...

The Angular material slider experiences issues with functionality when paired with the *ngFor directive

Having a unique problem that I could easily replicate on stackblitz. When using multiple mat sliders generated from a *ngFor loop with numbers as values, encountering an issue where moving the first slider affects all others. Subsequent drags only update ...

Serve both .ts and .js files to the browser using RequireJs

In my ASP.NET Core Project, the following files are present: greet.ts export class WelcomMesssage { name: string; constructor(name: string) { this.name = name; } say(): void { console.log("Welcome " + this.name); } } GreetExample.ts import * as ...

The issue of process.server being undefined in Nuxt.js modules is causing compatibility problems

I've been troubleshooting an issue with a Nuxt.js module that should add a plugin only if process.server is true, but for some reason it's not working as expected. I attempted to debug the problem by logging process.server using a typescript modu ...

Tips for managing Razorpay responses in Angular 2

I'm currently in the process of finalizing my payment transaction through RazorPay Payment gateway, and I've attempted to do so as shown below: var options = { "key": "XXX", "amount": 100, "name": "Ezshipp", "description": this.it ...

I'm having trouble establishing a connection with the Appwrite platform

Encountered an issue while trying to connect to appwrite. The specific error message is: Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL at Account.<anonymous> (appwrite.js?v=d683b3eb:932:19) at Generator.nex ...

Setting up React Context API with TypeScript: A Step-by-Step Guide

I recently updated my app.js file to app.tsx for improved functionality. However, I encountered an error with the current value. app.tsx import React, { createContext, useState } from "react"; import SelectPage from "./pages/select/select& ...

Constructing objects in TypeScript is a breeze with its C#-ins

It seems like finding a simple solution for my task is proving to be quite challenging. I have a class that accepts 10 parameters, most of which are optional. To simplify things, I will illustrate my dilemma using just 3 parameters. I wish to be able to i ...

What is the best approach to perform type checking on a function that yields varying types depending on the values of its

Currently, I am facing a challenge with a function that takes an argument and returns a different type of value depending on the argument's value. For instance: function foo(arg: 'a' | 'b') { if (arg === 'a') { ret ...

I'm struggling to make basic CSS work in my Next.js 13 project. I'm a beginner, can someone please help?

I am facing issues with the default CSS in my latest project. I have a file called page.modules.css and I am using classname = styles.style page.tsx import styles from'./page.module.css' export default function Home() { return ( <div cl ...

I encountered a problem where the error "Type '(err: Error) => void' does not possess any properties similar to type 'QueryOptions'" appeared, and I am unsure of the underlying cause

Check out my route for removing a user: https://i.stack.imgur.com/fevKI.png I've set up a route called "/deleteuser" that uses the POST method. It validates the request body for an id and then proceeds to delete the user with that ID from the databas ...

Using Angular: Binding Angular variables to HTML for display

I have a component with a ts file that contains HTML content as a variable. Let's say para1= <a href="www.google.com">sitename</a> more content I want to bind this paragraph in HTML as if it were actual HTML tags. sitename What is the ...

Can a type guard be implemented to verify if an object field is undefined?

Looking for a way to create typings for the code I am working on. Let's say I have the following interfaces: interface Car { id: string; type: number ownerId: number | undefined; // ... other fields } interface Plane { id: number; ...

In TypeScript, use a Record<string, any> to convert to {name: string}

I have developed a custom react hook to handle API calls: const useFetch: (string) => Record<string, any> | null = (path: string) => { const [data, setData] = useState<Record<string, any> | null>(null); var requestOptions: Requ ...

Tips on modifying the selected type key name through Pick?

I currently have this structure: type Product = { name: string } and I am looking to extract the name property and use it in a different type declaration like so: type NewProduct = Pick<Product, 'name'> Now, I want to rename name as new ...

Is it possible to ensure that all values from a specific type are represented in an enum collection?

I have a Prisma enum that I've defined (not in TypeScript), and I'm curious if it's possible to synchronize a TypeScript String enum with the generated Type from the Prisma Client. Here are the key details: export const GroupInvitationSta ...

Ways to display "No records" message when the filter in the material table in Angular returns no results

How can I implement a "No Records Message" for when the current table is displaying empty data? Check out this link for examples of material tables in AngularJS: https://material.angular.io/components/table/examples ...