Tips for determining the type of an object's property based on the key name

My goal is to set specific types based on the property name:

  • If the property name starts with on, it should be of type Function
  • For all other cases, the type should be boolean

Initially, I attempted this using an interface:

interface Props {
  [key: `on${string}`]: Function; // error: 'on${string}' index type 'Function' is not assignable to 'string' index type 'boolean'.ts(2413)
  [key: string]: boolean;
}

After that, I tried a different approach utilizing a type and interface:

type EventName = `on${string}`;

interface Props {
  [K: EventName | string]: typeof K extends EventName ? Function : boolean;
}

const props: Props = {
  asd: true,
  onClick: () => {}, // error: Type '() => void' is not assignable to type 'boolean'.ts(2322)
};

Is there another way to achieve this without encountering these errors?

Answer №1

It is not completely feasible to ensure the code is error-free due to limited checks. If s holds a string, there is no foolproof way to prevent it from encompassing a string that commences with on. Hence, the index signature for the string needs to align with all designated properties.

let s = "onClick" as string;
let v = props[s] // typed as boolean, but actually onClick

To address this issue (not without risks), one can employ an intersection instead of an interface. While this approach enables property access as desired, creating such objects necessitates a type assertion due to lingering incompatibility.

type Props = {
  [key: `on${string}`]: Function; 
} & {
  [key: string]: boolean;
}

const props: Props = {
  asd: true,
  onClick: () => {}, 
} as any as Props;

props.onClick // Function
props.ssss // boolean

Playground Link

For object creation and to eliminate the need for the any type assertion, a validation function can be utilized to ensure keys without the prefix on are indeed of type boolean:

function makeProps<T extends Record<`on${string}`, Function>>(o: T & Record<Exclude<keyof T, `on${string}`>, boolean>) {
    return o as Props;
}
const props: Props = makeProps({
  asd: true,
  onClick: () => {}, 
})

Playground Link

A safer alternative would involve making the keys for boolean and Function mutually exclusive by introducing a prefix for the boolean properties too.

type Props = {
  [key: `on${string}`]: (...a: any[]) => any; 
  [key: `flag${string}`]: boolean;
}

const props: Props = {
  onClick: () => {}, 
  flagRaiseClick: true
}

props.onClick // Function
props.flagRaiseClick // boolean

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

The module 'json-stringify-safe' could not be located

Encountering an issue while executing the command - ionic serve The code was functioning properly on a different system but seems to be causing trouble for me at the moment. https://i.sstatic.net/X1JG0.png ...

I'm looking to retrieve a specific file from my Angular Firestore database

I encountered a challenge in my latest project. I implemented Nested Children Routing to display data, and I want the specific item's data to be visible when clicking on the button. The routing is set up correctly, but I'm struggling to find the ...

Using Ionic 2 pipe to filter a dynamically changing list based on the name property

Q) What could be causing the error in my code's syntax? I am attempting to filter a list of items by their name property. However, the following code is resulting in the error: Cannot read property 'toLowerCase' of undefined Please note: ...

Improving Performance: Addressing Charset Definition Issue in NextJS Lighthouse Best Practices

Encountering an error on my blog page that states: Properly define charset Error! A character encoding declaration is required. It can be achieved with a tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. Find out more a ...

What's the best way to include various type dependencies in a TypeScript project?

Is there a more efficient way to add types for all dependencies in my project without having to do it manually for each one? Perhaps there is a tool or binary I can use to install all types at once based on the dependencies listed in package.json file. I ...

Enhancing Angular Material forms with custom background colors

I'm new to Angular and Angular material, still learning the ropes. I have been trying to create a form and needed to change the background color to Red. However, when I attempted to do so, the red color ended up covering the entire form instead of ju ...

Seamless database migrations using sequelize and typescript

I've been exploring the concept of generating migration files for models that already exist. When I use the "force: true" mode, tables are automatically created in the database, so I find it hard to believe that creating migration files automatically ...

Understanding React and TypeScript Higher Order Components: How to Resolve the Type '{}' is not assignable to Type P Error

While following along with the Learning React with TypeScript book, I encountered a problem where I hit a wall while coding. Despite surrendering and copying code directly from the book, the compiler is still unhappy As a temporary solution, I have resort ...

Implement pagination in Angular for the table

I am currently working with a mat-table and facing an issue. Here is the link to my table: https://stackblitz.com/run?file=src/app/table-dynamic-array-data-example.ts . I want to implement pagination for this table, but the dataSource structure differs fro ...

Why are the queries undefined when making HTTP requests with Express?

I'm encountering an issue with using express for HTTP get requests. It seems that req.query.page is consistently coming up as undefined. Can anyone point out what mistake I might be making? The API address in question is http://localhost:3232/api/tic ...

How can you use console.log() effectively in an Angular application?

While debugging an Angular project, I have encountered a situation where console.log() does not seem to be working properly despite ensuring that all logging levels are enabled in the Chrome console settings. I have tried placing the console.log() statemen ...

What is the most efficient way to retrieve all documents from Firestore at once?

After subscribing to valueChanges, I initially receive an object of length 1, as shown in the console.log (image below), and shortly after that the object with all values. However, this is not what I need. I require getting all values from the start so tha ...

Converting typescript path aliases into local file paths

Just dipping my toes into typescript and grappling with module resolution. The problem seems straightforward (or so I think), but there's something off about my tsconfig.json. If my folder structure looks like this: + release + definitions + ...

What is the process for integrating Typescript into a Quasar 2 project that is utilizing Vite as its build tool?

The Quasar 2 documentation provides in-depth guidance on integrating Typescript with Webpack: Unfortunately, my Quasar project is configured with Vite and I am struggling to locate resources on incorporating Typescript into an already existing project. A ...

Dealing with mouseover and mouseout events for ul li elements in Angular 9: An easy guide

Having trouble showing and hiding the span tag using mouseover and mouseout events. The ul and li elements are generating dynamically, so I attempted to toggle the display between block and none but it is not working as expected. Does anyone have a solutio ...

Exploring the TypeScript Type System: Challenges with Arrays Generated and Constant Assertions

I am currently grappling with a core comprehension issue regarding TypeScript, which is highlighted in the code snippet below. I am seeking clarification on why a generated array does not function as expected and if there is a potential solution to this pr ...

Communication between main thread and Web Worker is unreliable in React application with TypeScript and Webpack

I've been attempting to post a message to a web worker in a React app using TypeScript and Webpack, but I'm facing an issue where it's not working as expected and no errors are being thrown. Here is how I set up the Web Worker: insights.ts ...

Tips for retrieving keys of a specific type from an object

If I were to create an interface named Data: interface Data { key1: number key2: boolean set1: SomeInterface[] set2: AnotherInterface[] } Is there a way to retrieve the properties of the interface Data that includes [] in the form of a discriminat ...

Merging an unspecified number of observables in Rxjs

My latest project involves creating a custom loader for @ngx-translate. The loader is designed to fetch multiple JSON translation files from a specific directory based on the chosen language. Currently, I am implementing file loading through an index.json ...

Encountering a script error when upgrading to rc4 in Angular 2

After attempting to update my Angular 2 version to 2.0.0.rc.4, I encountered a script error following npm install and npm start. Please see my package.json file below "dependencies": { "@angular/common": "2.0.0-rc.4", "@angular/core": "2.0.0-rc.4", ...