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

Even though I included a key prop for each item, I am still encountering the error message stating that every child in a list should have a distinct "key" prop

I have been trying to retrieve data from a rest API and display it as text on my browser. However, I am encountering the following error: index.js:1 Warning: Each child in a list should have a unique "key" prop. Below is how I have set up the key prop. ...

Guidelines for integrating Pinia seamlessly into Vue 3 components

How should Pinia's store be correctly used in Vue 3 components? Option A const fooStore = useFooStore(); function bar() { return fooStore.bar } const compProp = computed(() => fooStore.someProp) Option B function bar() { return useFooStore( ...

Utilizing Images with 'General Drawing' in Highcharts

I'm currently attempting to create a task diagram using Highcharts. I had the idea of incorporating images using the <img> tag ren.label('<img src="/images/test.jepg', 10, 82) .attr({ ...

Create type declarations using the Typescript compiler by running the command:

After generating my definition file ".d.ts" using tsc --declaration or setting declaration as true in the tsconfig.json, I noticed that the generated files are missing declare module "mymodule" {... } This appears to be causing issues with "tslint" which ...

The public folder in Node.js is known for its tendency to encounter errors

I'm facing an issue with displaying an icon on my website. Here is the current setup in my code: app.js const http = require('http'); const fs = require('fs'); const express = require('express') const path = require(&apo ...

Could there be an issue with the way I've implemented my setInterval function?

I am currently in the process of developing a stopwatch feature using React Native and implementing the setInterval function to increase a counter and update the state accordingly: Play Function (triggered upon pressing the play button) const [isRunning ...

Is it possible to assign default values to optional properties in JavaScript?

Here is an example to consider: interface Parameters { label: string; quantity?: number; } const defaultSettings = { label: 'Example', quantity: 10, }; function setup({ label, quantity }: Parameters = { ...defaultSettings }) { ...

tsc does not support the use of the '--init' command option

Encountering an error when running npx tsc --init: $ npx tsc --init npx: installed 1 in 1.467s error TS5023: Unknown compiler option 'init'. I've added the typescript package using Yarn 2: $ yarn add -D typescript ➤ YN0000: ┌ Resolution ...

Tips for utilizing the onload function in jquery

Having an issue where I have a button that I want to set time, and in order for the function to run correctly, it needs to be defined on the body element. This works fine with plain JavaScript, but I am encountering an error when trying to use jQuery. < ...

My requests and responses will undergo changes in naming conventions without my consent or awareness

Initially, I wrote it in a somewhat general manner. If you require more information, please let me know! This is how my C# class appears when sent/received on the frontend: public class Recipe : ICRUD { public Guid ID { get; set; } ...

Is it possible to launch a React application with a specific Redux state preloaded?

Is there a way to skip navigating through a bulky frontend application in order to reach the specific component I want to modify? I'm curious if it's feasible to save the redux store and refresh my application after every code alteration using t ...

What is the best way to retrieve the value of a nested function in JavaScript?

I am currently working on a project that involves a function. function findParentID(parentName) { Category.findOne({ categoryName: parentName }, function (err, foundParent) { var parentID = foundParent.categoryID;    return parentID;<br> } ...

Interacting with shadow DOM elements using Selenium's JavaScriptExecutor in Polymer applications

Having trouble accessing the 'shop now' button in the Men's Outerwear section of the website with the given code on Chrome Browser (V51)'s JavaScript console: document.querySelector('shop-app').shadowRoot.querySelector ...

deleting the existing marker before placing a new marker on the Mapbox

Upon the map loading with GeoJson data, I have implemented code to display markers at specified locations. It works flawlessly, but I am seeking a way to remove previous markers when new ones are added. What adjustments should be made for this desired func ...

Ways to iterate through a JSON formatted array variable using JavaScript

Below is my code snippet, used to plot all the locations fetched from my database onto a Google map. $.ajax({ url:"http://localhost/church_finder/index.php/MapController/search_church", type:'POST', data: ...

Configuration options for Path Aliases in TypeScript

In my Next.js project, I am utilizing TypeScript and have organized my files as follows: |-- tsconfig.json |-- components/ |---- Footer/ |------ Footer.tsx |------ Footer.module.sass My path aliases are defined as:     "paths": {       ...

Resetting several sticky titles after displaying and hiding elements

Inspired by a popular codepen example, I have successfully implemented sticky titles in my sidebar. However, when integrating these sticky titles with the functionality to show/hide related items on click, I encountered some unexpected issues. The code sni ...

Utilize Google Tag Manager to search and substitute characters within a variable

Within my GTM setup, I have a CSS selector variable in the DOM. This variable pertains to real estate and specifically represents the price of a listing. My goal is to eliminate the characters ($) and (,) from this variable as part of meeting the requireme ...

What issues can trailing white space cause in TypeScript coding?

While I understand that linting is the reason for this, why are trailing spaces considered problematic? I plan to disable this feature in tslint.json, but before I make that change, I want to ensure I'm not making a mistake. Visual Studio Code alert ...

Form fields will not automatically populate with link parameters; the user must manually input the information

My form fetches data from the database using server-side code when the user inputs the "user_id" field. The User ID field is the primary field on the form, and when the user enters their user ID, all other fields retrieve the corresponding user data from t ...