Determine the type of a variable at compile time using TypeScript

In my programming project, I have a base class called GenericSetting that is subclassed in approximately 10 or more types.

export class GenericSetting {
  configuration: SettingArgs
  constructor(args: SettingArgs) {
    this.configuration = args
  }
}

As you can see, it also receives arguments which are subclassed themselves to include additional properties required by the subclasses.

I then proceed to create hundreds of settings, keeping them as concise as possible.

FocusPos = new LensValuedSetting({ componentId:LensModule, key:"Focus-ActuatorPosition", displayName:"@{ActuatorPosition}", categories:["@{Lens}", "@{Focus}"], mode:EditMode.ReadOnly, stepSize:0, ctx:{ canId:7, dataType:"UInt16", bit:-1, startByte:2, rounding:1 }})
FocusAuxActive = new LensValuedSetting({ componentId:LensModule, key:"Focus-AuxInputDeviceActive", displayName:"@{AuxInputDeviceActive}", categories:["@{Lens}", "@{Focus}"], mode:EditMode.ReadOnly, stepSize:0, ctx:{ canId:36, dataType:"Byte", bit:1, startByte:6, rounding:1 }}, )
FocusAuxPos = new LensValuedSetting({ componentId:LensModule, key:"Focus-AuxInputDevicePosition", displayName:"@{AuxInputDevicePosition}", categories:["@{Lens}", "@{Focus}"], mode:EditMode.ReadOnly, stepSize:0, ctx:{ canId:36, dataType:"Int16", bit:-1, startByte:2, rounding:1 }}, )

The issue arises because TypeScript infers the arguments passed, making the args argument of type object at runtime, bypassing the constructors of all these subclassed setting arguments.

To address this, I considered creating the type being type-guarded in TypeScript within the base constructor and using Object.assign() like so:

export class GenericSetting {
  configuration: SettingArgs
  constructor(args: SettingArgs) {
    const typedArgs = new <HOW DO I GET CTOR OF ARGS TYPE?>
    Object.assign(typedArgs, args)
    this.configuration = typedArgs
  }
}

However, since I lack information about the type-guarded/inferred type at runtime, is there no way to achieve this in one place? Must I write this logic in every subclass?

Answer №1

After struggling with generics in a complex class hierarchy, I finally came up with a solution that seems to work well. The key was adding an extra property to the ...Args type called _cfgType:any. Now, I can pass this property into the ...Args object like so:

  FocusPos = new LensValuedSetting({ _cfgType:LensValuedSettingArgs, componentId:LensModule, key:"Focus-ActuatorPosition", displayName:"@{ActuatorPosition}", categories:["@{Lens}", "@{Focus}"], mode:EditMode.ReadOnly, stepSize:0, ctx:{ canId:7, dataType:"UInt16", bit:-1, startByte:2, rounding:1 }})

The constructor for my GenericSettings base class now looks like this, where it converts the incoming args to the correct type and applies default values from the subclass:

export class GenericSetting extends ItemBase {
  configuration:SettingArgs

  constructor(args:SettingArgs) {
    if (!isNullOrUndefined(args._cfgType)) {
      const typedArgs = new args._cfgType()
      Object.assign(typedArgs, args)
      args = typedArgs
    }
    args['__type'] = args['__proto__'].constructor.name
    super(args)
    this.configuration = args
  }
}

This might not be the most elegant solution, but it allowed me to make minimal changes to my existing code.

Answer №2

It appears that utilizing generics is the solution for your requirement.

export class CustomGeneric<T extends Setup> extends ItemBase {
  configuration: T
  constructor(setupType: new (arguments: ConfigurationArgs): T, arguments: ConfigurationArgs) {
    const instantiatedArgs = new setupType(arguments)
    ...
  }
}

However, do we really need to instantiate instantiatedArgs within CustomGeneric? This instantiation process seems independent of CustomGeneric, so it may be more beneficial to conduct the instantiation externally.

For example:

constructor(public instanceConfig: ...) { }

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

Encountering a deadly mistake with LNK1181 while attempting to npm install web3

On my Windows system, I attempted to install the web3 node package using npm install. I followed the necessary steps by first installing Windows build tools: npm install --global --production windows-build-tools This command executed without issues, but ...

Missing Personal toolbar button on Forge Viewer interface

After completing the tutorial for learning Autodesk Forge, I successfully linked my BIM 360 account to the Forge Viewer. My next goal is to add extensions and have a button on the toolbar that directs to these extensions. However, when following the exten ...

Unable to access the 'data' property because it is undefined in AngularJS, making it impossible to retrieve data from the template to the controller

I am new to angularjs and still learning its intricacies. Currently, I am facing an issue where I can't seem to find a simple solution. I hope someone can assist me with this. Here is the folder structure that I have created: Select ->SelectModu ...

Error: The gulp-cssmin plugin encountered a TypeError because it attempted to read the property '0' of a null

I am attempting to condense my code, but I am encountering this error: D:\gulp-compiler\node_modules\gulp-cssmin\node_modules\clean-css\lib\selectors\extractor.js:66 return name.replace(/^\-\w+\-/, ...

Issue with Dates in Typescript array elements

When attempting to compare different Date elements in my code, I encountered an issue. I have two date elements representing date formats but am unable to compare them because I keep receiving the error message "core.js:6237 ERROR TypeError: newticketList. ...

Incorporating external JavaScript libraries in Jint

I'm currently working on a new feature that requires the execution of user-defined, anonymous JavaScript functions retrieved from a database on the server side within an ASP.Net application environment. For this purpose, I am exploring the use of Jin ...

Tips for setting a default value for the local file in React Native

I am attempting to assign a default value to my Avatar component in React Native Elements as I do not have all the required icon files prepared. However, when I use the OR logic, it does not seem to work as expected. What is the correct approach to achie ...

Activate a Bootstrap tab using turbolinks dynamically

After loading the page, I am attempting to open a Bootstrap 4 tab. It works when I refresh the page, but if I navigate within the site, it gives me a query selector empty error. This code is a port of the solution mentioned in this tutorial, as I am using ...

Script for converting Fixed Positioned Elements to Static

I am frequently finding that elements on web pages are causing disruptions due to their fixed positioning. I am exploring ways to disable the position: fixed CSS rules on any website I visit. To address this issue, I have developed a userscript specifical ...

Making a quick stop in Istanbul and NYC to collect a few important files

Setting up Istanbul/Nyc/Mocha for test coverage in my project has been a bit of a challenge. While I was successful in running Nyc, I noticed that not all the .ts files in my project were being picked up for test coverage. When I execute npm run coverag ...

Leveraging Parameters from URL in Javascript

I'm facing an issue with my area shape, the href="/kosmetikstudios/deutschland/Bayern" tag seems to be causing a problem. I want to utilize the parameter "Bayern" (which is the last parameter in the URL). I need this to be dynamic. Below is my JavaS ...

Troubles with Katex/ngx-markdown Display in Angular 16

In my Angular 16 application, I utilize the ngx-markdown library alongside Katex and other dependencies. A challenging situation arises when the backend (an LLM) responds with markdown text that conflicts with Katex delimiters during rendering. I attempte ...

JQuery Ajax encounters a 500 error message due to an internal server issue

I'm currently using the jQuery library to send an ajax request to a PHP file. Initially, everything was working perfectly fine with a relative path like this: url:"fetch_term_grades.php", However, when I modified the path to be more specific like th ...

Mysterious failure of JavaScript regular expression when encountering the term "tennis"

We developed a JavaScript script to detect duplicates or potential duplicates, but it seems to have some issues with certain words like "tennis." The script functions correctly in most cases, but fails when analyzing phrases related to the word "tennis" fo ...

Creating a dynamic sidebar based on roles in AngularJS

I'm looking to create a dynamic sidebar based on the user's role, which is stored in $rootScope.login. However, I'm unsure of how to integrate it into template.js. Below is my JavaScript code and I'm still relatively new to AngularJS. ...

Is there a way to execute code right before the jQuery submit() function is run?

I'm currently facing an issue with executing codes before a validation function runs in my form. I have tried different methods including referring to How to order events bound with jQuery, but without success. This is the code snippet I am working w ...

Preventing users from copying and pasting information from my form by implementing javascript restrictions

I'm looking for a solution to prevent users from copying and pasting in my form using JavaScript. I want to restrict the ability to paste or copy any content into the form. Any assistance would be greatly appreciated! ...

Using NodeJS to facilitate communication between multiple NodeJS instances while also overseeing operations of a Minecraft server

I have a question about communicating between NodeJS instances. Let's say I have one NodeJS instance running a chat room - how can I access that chat and see who is connected from another NodeJS instance? Additionally, I'm curious if it's f ...

Unable to trigger click event following regeneration of elements

I am having trouble with a click event on checkboxes when I remove and insert new table bodies. How can I fix this issue? I have tried using append(), clone() but it didn't work for my code. To demonstrate the problem, I have created a JSFIDDLE which ...

Setting the width of a parent div tag in CSS based on its children tags

My goal is to have a parent div tag with several children div tags placed horizontally. Since the number of children tags is not known in advance, I cannot set the width of the parent div tag using CSS alone, so I am using JavaScript for this purpose. var ...