Restrict a class to contain only functions that have a defined signature

Within my application, I have various classes dedicated to generating XML strings. Each of these classes contains specific methods that take input arguments and produce a string output. In order to enforce this structure and prevent the addition of methods with different signatures or non-method members, I've implemented the following approach:

interface IRequestParser {
  [funcName: string]: (...args: any[]) => string;
}

Here's an illustration using a sample class:

class myParser implements IRequestParser {
  [funcName: string]: (...args: any[]) => string;

  func1(a) {
    return '';
  }
}

This design restriction prohibits the inclusion of properties that are not methods within myParser:

  a: string; // not allowed
  b() { // not allowed
    return 5;
  }

However, it enables me to invoke any function from an instance of myParser without raising an alert:

const instance = new myParser();
console.log(instance.func1('sample'));
console.log(instance.func2(4, 5, ['a', 'b']));

While calling func1 is expected behavior and would trigger an error if missing the required argument, there is also the ability to call a non-existent function like func2 or any arbitrary name.

Is there a method to restrict the type of class members while preventing the invocation of undefined functions?

Answer №1

Here is an alternative approach:

class CustomParser implements Schema<keyof CustomParser, (...args: any[]) => string> {

  // valid
  func1(a: any) {
    return '';
  }

  // error: string cannot be assigned to (...args: any[]) => string
  a: string; 

  // error: number cannot be assigned to string
  b() { 
    return 5;
  }
}

const customParser = new CustomParser();
customParser.func1("valid"); // works
customParser.funcNope("invalid"); // error, no property funcNope

Implementing a specific mapped type like Schema<> is allowed, and there are instances where circular references can work (using keyof to reference keys is generally fine).

I hope this information proves useful to you. Best of luck!

Answer №2

The structure you are utilizing enables the class to be accessed through any string value. It seems challenging to enforce the specific constraint you have in mind using this approach, at least from my current perspective. There might be alternative solutions suggested by others.

One potential workaround is to utilize a function that restricts the class to contain only functions with a particular signature while still preserving its original properties:

type ParserFunction = (...args: any[]) => string;
function createRequestParserClass<
  T extends new (...a: any[]) => Record<keyof InstanceType<T>, ParserFunction>>(constructor: T) {
  return constructor
}
const myParser = createRequestParserClass(class {
  // a: string; // not permitted
  // b() { // not allowed
  //   return 5;
  // }

  func1(a: string) {
    return '';
  }
});

typedef myParser = InstanceType

const instance = new myParser();
console.log(instance.func1('test'));
console.log(instance.func2(4, 5, ['string', 'value'])); // will show an error now 
console.log(instance.func1(1)); // also results in an error

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

shortcut taken in inferring now exported

When using a default export, if the expression consists only of a variable identifier, the type inferencer defaults to the declaration of the variable instead of the actual type of the expression. Is this behavior intentional or is it a bug? // b.ts const ...

Tips for sending information to an Express API through AJAX

While working on a website using Express and EJS, I encountered an issue with calling an API via AJAX. The problem arises when passing two values to the AJAX data upon button click, resulting in errors. Despite trying various solutions, I'm still stru ...

Incorporate a personalized style into the wysihtml5 text editor

Is there a way for me to insert a button that applies a custom class of my choice? I haven't been able to find this feature in the documentation, even though it's a commonly requested one. Here's an example of what I'm looking for: If ...

In JavaScript, the input box is set to automatically capitalize the first letter, but users have the ability

How can I automatically capitalize the first letter of a user's name input, but allow for overrides like in the case of names such as "de Salis"? I've read on Stack Overflow that CSS alone cannot achieve this with text-transform:capitalize;, so ...

Updating front end data using Node.js - A Comprehensive Guide

I am looking to create a website using node.js that can dynamically display a plot and update the data every minute without needing to refresh the entire page. As someone new to node.js, I am interested in learning how to use "get" requests to update the d ...

Utilizing Props in Vue.js to Access Data for v-model

After browsing online, I attempted to pass props to data in the following manner: Child Component: props: { idInput: { type: String, required: false }, nameInput: { type: String, required: false }, }, data() { return { id: this.idInput, na ...

I am encountering a challenge retrieving the ID via AJAX from the view to the controller. However, the ID is successfully displaying in the alert

In the view page code below, I am trying to send an ID through Ajax but it is not posting in the controller. The goal is to replace one question at a time fetching from the database. $(document).ready(function() { $("#next").click(function() { ...

Issue with date range filter functionality not functioning as expected

Struggling to get the date range filter to function properly. Selecting a date triggers it, but nothing is being added to the var filter. I've spent hours trying to solve this issue with no progress. html <div class="form-group"> <input ...

After resolving a promise, what is the process for loading a Next.js App?

Seeking guidance on implementing the code snippet below using Next.js. I suspect there is an issue with Next.js not being able to access the window object without being within a useEffect(() => {}) hook. When switching back to regular React, the code ...

Understanding the Difference Between WARN and ERR in npm Peer Dependency Resolution

I encountered a puzzling situation where two projects faced the same issue, yet npm resolved them differently: https://github.com/Sairyss/domain-driven-hexagon npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! W ...

What is the best approach for sending mapbox coordinates to a higher-level class in a react application?

As a beginner in learning React, I'm currently working on setting a map marker with a click event on a Mapbox GL map. The challenge I'm facing is passing the lngLat object back up to the parent component. Can someone guide me on how to achieve th ...

How can user input be converted into a JavaScript variable?

Looking for help with my webpage - I want users to input their name and age. After hitting submit, I'd like the first input to be stored in a variable called 'name', and the second input in a variable called 'age'. Is this doable? ...

How can I integrate custom PHP pages into Odoo Community 12?

I am looking for a way to integrate my custom PHP webpages with the login page of Odoo Community that is already set up and functioning on my server. I want specific users to be redirected to my custom pages after logging in. Any suggestions on how to ac ...

Why is the ionChange/ngModelChange function being triggered from an ion-checkbox even though I did not specifically call it?

I have an issue with my code involving the ion-datetime and ion-check-box. I want it so that when a date is selected, the checkbox should automatically be set to false. Similarly, if the checkbox is clicked, the ion-datetime value should be cleared. Link ...

The issue of Angular UI Bootstrap buttons not updating persists even after the removal of an

My Radio-bottoms are powered by an Array for a Multi-Choice answer setup. <div ng-repeat="option in options"> <div> <button type="button" style="min-width: 100px" class="btn btn-default" ng-model="question.answer" btn-radio="' ...

A guide to validating a v-edit-dialog within a v-datatable

As I navigate my way through vue.js and vuetify, I am faced with an issue regarding the validation of input within a v-edit-dialog located inside a v-datatable. Despite having functional validation in place, the save button remains enabled and accepts inva ...

Incorporating outside content into HTML

Currently, I am working on a project at my job which requires me to create a comprehensive help file with multiple chapters and extensive text all within one large HTML file. However, as the text will need to be translated into different languages, I am lo ...

Tips for avoiding the freezing of bootstrap-select scroll when a large number of options are present

I have integrated a bootstrap-select with a total of 1000 options. However, I am encountering an issue where when I attempt to scroll down the list of options, it only goes down approximately 60 options and then freezes in that position. Can anyone provi ...

Verify the specific type conditions of a key value in a mapped type

I am attempting to achieve the following: If the actions property exists, and there are callbacks within the actions properties that return a string, then return X or Y. The above code is expressed as: // type MappedType<T> = { // [K in keyof T]: ...

The C# MVC Controller is having difficulty retrieving decimal or double values from an Ajax POST request

Having trouble sending decimal or double values via ajax to my C# MVC Controller. The values always come through as null, even though they work fine when sent as strings or integers. Why is this happening? When checking the client's request, the corre ...