Is there a way to merge two generic keys for a specific data type?

I've been working on creating a TypeScript helper for React's useState hook. The goal is to simplify components' (functions) arguments/props like the following:

import { type Dispatch, type SetStateAction } from 'react';

export const ComponentOne = ({ clicked: boolean; setClicked: Dispatch<SetStateAction<boolean>> })

It can be quite cumbersome to repeat this code, so I came up with a builder type:

export type Name<N extends string> = `set${Capitalize<N>}`;

export type Builder<N extends string, S> = {
  [key in N]: S;
} & {
  [key in Name<N>]: S;
};

After tweaking the code a bit:

export type Props = {
  className: string;
} & SetStateBuilder<'clicked', boolean>;

export const ComponentOne = ({ className, clicked, setClicked}: Props)...

It works, but the issue is that TypeScript is displaying them separately:

type Props = {
    className: string;
} & {
    clicked: boolean;
} & {
    setClicked: boolean;
}

This is not ideal! I would like to combine clicked and setClicked together. The keys from Props are fine as they are.

However, when I try to include [key in N]: S; and [key in Name<N>]: S; inside the Builder, TypeScript sees them as the same and removes one.

Any assistance would be greatly appreciated.

Answer №1

If you're looking to enhance your code with a more streamlined approach, consider utilizing the Prettify utility type from the type-samurai package. Here is a simplified version:

type Prettify<T> = T extends infer R
  ? {
      [K in keyof R]: R[K];
    }
  : never;

By leveraging the mapped type, this utility can effectively transform the given type, eliminating intersections, type aliases, and other complexities.

For testing purposes, consider the following example:

type Prettify<T> = T extends infer R
  ? {
      [K in keyof R]: R[K];
    }
  : never;

export type Name<N extends string> = `set${Capitalize<N>}`;

export type Builder<N extends string, S> = Prettify<
  {
    [key in N]: S;
  } & {
    [key in Name<N>]: S;
  }
>;

// type Result = {
//   clicked: boolean;
//   setClicked: boolean;
// }
type Result = Builder<'clicked', boolean>;

Explore this interactive playground to see this utility in action.

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

Having trouble displaying the button upon initial load using ngIf

My goal is to display a button when editing an input form. Initially, the button is hidden when the page loads but it should appear once any of the input fields are edited. I have also implemented highlighting for the input box that is being edited. Howeve ...

Change number-type object fields to string representation

I am in the process of creating a function that takes an object as input and converts all number fields within that object to strings. My goal is for TypeScript to accurately infer the resulting object's fields and types, while also handling nested st ...

Encountering an issue with setting up MikroORM with PostgreSQL due to a type

I'm currently working on setting up MikroORM with PostgreSQL, but I've encountered a strange error related to the type: Here is the code snippet: import { MikroORM, Options} from "@mikro-orm/core"; import { _prod_ } from "./consta ...

The combination of UseState and useContext in React Typescript may lead to compatibility issues

I attempted to integrate the context API with the useState hook but encountered difficulties when using TypeScript. First, let's create App.tsx: const App = () => { const [exampleId, updateExampleId] = useState(0); return ( <div> ...

Exploring Service Injection and Factory Pattern in Angular 8

After going through various articles and official Angular guides, it appears that they were unable to assist me in solving my task. Here's what I wanted to achieve: Imagine having an Angular application with a product listing page. Additionally, this ...

What is the counterpart of $.isEmptyObject({}) in Typescript for checking if an object is

Is there a formal method for testing an Object (response from server) to see if it is empty? Currently, I am using jQuery to accomplish this. this.http.post(url, data, {headers: headers}).then( result => { if (!$.isEmptyObject(result ...

What is the best way to utilize the fresh Sanitizer API in Typescript?

Everything seems to be working well on Codepen, even without using window. It's surprising because I'm used to having to use window.x if ( 'Sanitizer' in window ) { console.log( 'sani', 'Sanitizer' in window ); } ...

Is there a way to retrieve the final value from an Observable?

Trying to retrieve the last value from an observable. Here is an example of the code: // RxJS v6+ import { lastValueFrom, Subject } from 'rxjs'; import { scan } from 'rxjs/operators'; async function main() { const subject = new Subje ...

What is the best method for calculating the total of a column field within an array in Angular 9.1.9?

I am using Angular 9.1.9 and Html to work with a nested array field in order to calculate the total sum and display it in a row. Within my array list ('adherant'), I am aiming to sum up a specific column's values ({{ Total Amount }}) and pr ...

Is there a way to dynamically define the return type of a function in Typescript?

Can the variable baz be dynamically assigned the string type? type sampleType = () => ReturnType<sampleType>; // Want to return the type of any function I pass (Eg. ReturnType<typeof foo>) interface ISampleInterface { baz: sampleType; } ...

Creating React components with TypeScript: Defining components such as Foo and Foo.Bar

I have a react component defined in TypeScript and I would like to export it as an object so that I can add a new component to it. interface IFooProps { title:string } interface IBarProps { content:string } const Foo:React.FC<IFooProps> = ({ ...

Bypass VueJs Typescript errors within the template section with Typescript

My VueJs App is functioning properly, but there is one thing that bothers me - a TypeScript error in my template block. Is there a way to handle this similar to how I would in my script block? <script setup lang="ts"> //@ignore-ts this li ...

Attempting to retrieve a file from the database with the utilization of Angular 5 and ASP.NET Core

I've been struggling with downloading a file from the database using its unique identifier. Can anyone provide guidance on what steps are necessary to achieve this successfully? The FileUpload table contains the following columns pertaining to the fi ...

Is there a way to customize the Color Palette in Material UI using Typescript?

As a newcomer to react and typescript, I am exploring ways to expand the color palette within a global theme. Within my themeContainer.tsx file, import { ThemeOptions } from '@material-ui/core/styles/createMuiTheme'; declare module '@mate ...

Importing a JSON or JSONC file into a vite/typescript project can be easily done

I am looking for a way to seamlessly share my routes between my actix-web backend and Vue with Vue-Router frontend without needing separate route files. I want to define the routes on the frontend without having to make any changes on the server side. If t ...

Guide on creating a similar encryption function in Node JS that is equivalent to the one written in Java

In Java, there is a function used for encryption. public static String encryptionFunction(String fieldValue, String pemFileLocation) { try { // Read key from file String strKeyPEM = ""; BufferedReader br = new Buffer ...

Tips for utilizing array.items in joiful validation?

Can someone provide an example code or a link on how to correctly use the joyful validation for array items? I attempted the array.items validation code using joyful, but I am not sure how to specify the items. Thanks in advance! ...

Angular 2: Integrating a service into a class

I am working on an Angular class that represents a shape. My goal is to be able to create multiple instances of this class using a constructor. The constructor requires several arguments that define the properties of the shape. constructor(public center: ...

How to dynamically assign a value in a React datepicker component in a React application

Having troubles with react-datepicker? I encountered an issue where setting the value of react-datepicker from props caused it to either not show the value or display a 'wrong time format' error. Here is a snippet of the Datepicker code: this.sta ...

Attempting to utilize pdf.js may result in an error specifying that pdf.getPage is not a recognized function

After installing pdfjs-dist, I attempted to extract all text from a specific PDF file using Node and pdfjs. Here is the code I used: import pdfjs from 'pdfjs-dist/build/pdf.js'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry.js&a ...