Tips for specifying the data type of a setter in JavaScript, VSCode, and TypeScript?

Let me provide a straightforward example to illustrate the problem:

class Person {
    _name = '';
    _age  = 0;
    get name() {
        return this._name;
    }
    /**
     * @type {string}
     */
    set name(name) {
        this._name = name;
    }
    get age() {
        return this._age;
    }
    /**
     * @type {number | string}
     */
    set age(age) {
        if (age === 'too old') {
            age = 100000;
        }
        this._age = age;
    }
}

Although I have clearly indicated that the age setter can accept either a number or a string, why does it still fail during typechecking in VSCode?

https://i.sstatic.net/RAz1H.png

Answer №1

Instead of explicitly specifying the type, you've opted to use a JSDoc comment which does not impact your code. TypeScript will automatically infer that the type is number.

If you need the setter to accept both string and number, consider using a union type as shown below:

set age(age: string | number) {
   ...
}

Be aware that you may encounter issues when working with this._age later on because it also defaults to being implicitly of type number (with a default value of 0) and therefore cannot accommodate values of type string | number.

Answer №2

To use the code snippet provided below, ensure you validate the type of age using the typeof operator to effectively implement an if statement.

class User {
  _username = '';
  _userAge = 0;
  
  get username() {
      return this._username;
  }
  
  /**
   * @param {string} name
   */
  set username(name) {
      this._username = name;
  }
  
  get userAge() {
      return this._userAge;
  }
  
  /**
   * @param {number | string} age
   */
  set userAge(age) {
      if (typeof age === 'string') {
        if (age === 'super old') {
          age = 90;
        } else {
          age = parseInt(age);
        }
      }
      
      this._userAge = age;
  }
}

Answer №3

In order for your union types to be valid in JSDoc, it is important to enclose them in parentheses:

/**
* @type {(string | boolean)}
*/

As stated in the official documentation:

When declaring multiple types (type union), such as a string or a boolean, use {(string|boolean)}. This notation indicates that a value can belong to one of several possible types, with each type enclosed in parentheses and separated by |.

Answer №4

The solution to the problem at hand is quite straightforward.

It's important to note that both getter and setter are properties of type function, even though they function as a single property where the value could be a function or something else entirely.

The issue arose when you mistakenly redefined the documentation symbol for Person.name as string instead of defining it properly as a function typically should. This error occurred within the context of the setter which should ideally return void.

To address this problem, consider using @returns {string} in place of @type {string}.

Below is the complete resolution:

      class Person
      {
         /**
          * The constructor parameters are specific to each instance.
          * 
          * @param { string } Name The `Name` parameter requires a `string`.
          */
         constructor (Name)
         {
            /**
             * Property definitions must occur within the constructor
             * to safeguard their private handling conditions.
             */
            Reflect.defineProperty
            (
               this, 'Name',
               {
                  // Configuration lockdown to prevent override
                  configurable: false,
                  
                  // Ensuring non-enumerability of property
                  enumerable: true,
                  
                  // Getter method returns Name parameter
                  get: () => Name,
                  
                  // Setter method updates Name parameter
                  set: (New) => { Name = String(New).toString() },
               }
            );
            
            // Initial assignment for parsing purposes
            this.Name = Name;
         }
         
         // Unsafe section due to potential descriptor replacement
         
         // Getter for Age property, indirectly exposed through  `Person.Age`
         // Assumes return value will be a `number`
         get Age ()
         {
            return this._Age;
         }
         
         // Setter for Age property, indirectly exposed through  `Person.Age`
         // Expects `New` parameter and converts it to `number`
         set Age (New)
         {
            this._Age = Number(New);
         }
      }
      
      const Human = new Person;

      // Setting name and age values
      Human.Name = 'Some Doe';
      Human.Age = 33;
      
      // Attempting to manipulate the `_Age` property directly
      Human._Age = 'tirty two';
      
      console.log({ ...Human });

I took some shortcuts in certain sections, but there shouldn't be any issues with this code snippet.

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

Utilizing pushState following a seamless ajax retrieval operation

I'm facing some challenges while trying to implement the pushState method. Despite triggering the history.pushState line, I'm unable to achieve the desired change in the browser window URL. Strangely, there are no error messages displayed in the ...

What is the best approach for managing errors within a shared observable in TypeScript?

I'm facing a unique issue and struggling to find someone who has encountered the same problem, which could imply that I am approaching it incorrectly. The http request I am making looks like this: return this.httpClient.post(`${this.route}/typegroups ...

Execute an asynchronous request using Javascript to communicate with a Spring Controller

I've created a JSP page that includes some JavaScript code: function sendData(tableID) { var table = document.getElementById(tableID); var dataArray= new Array(); for (var i = 1;i<table.rows.length; i++){ var row = table. ...

Performing unit testing on a Vue component that relies on external dependencies

Currently, I am in the process of testing my SiWizard component, which relies on external dependencies from the syncfusion library. The component imports various modules from this library. SiWizard.vue Imports import SiFooter from "@/components/subCompon ...

What is the best way to stylize a date using Bootstrap-datepicker?

While this topic is well-known, I have a slightly more complex question regarding it. I have gone through the documentation here. My goal is to display the date in French format (dd/mm/yyyy) and save the value in US format (yyyy-mm-dd). Additionally, I nee ...

What is the best way to limit a form to only allow 2 checkbox selections?

Seeking advice on implementing a form for a website giveaway featuring 3 prizes. Each participant should only be able to select 2 items from the list. I've already created a JavaScript-based form, but I'm concerned about its reliability since it ...

How can I choose one record based on another record in a database?

I have a unique structure where consts and record types are combined: const PageType = [ 'type1', 'type2', 'type3' ] as const; export type PageType = typeof PageType[number]; interface PageInfo { title: string } int ...

Accessing PHP output within Jquery

Even though I know PHP is a server-side script and JavaScript is client-side, I encountered an issue. I struggled to bypass browser security when making an AJAX request to another domain. Feeling lost, I decided to turn to PHP for help. The challenge I f ...

The event listener for the custom cursor in Nuxt.js is failing to work properly when the route

I am currently in the process of constructing a new website for our studio, but am encountering difficulties with getting the custom cursor to function correctly. I implemented a custom cursor using gsap, and it worked perfectly; however, once I navigate t ...

Navigating JSON sub-objects with JavaScript

I am currently working on implementing a filtering system for the "carObj" data below. As users select filters from a list on a webpage, I want to display only the sub-objects that match those selected filters. At the moment, when a user picks a filter, i ...

Is there a way to retrieve multiple results by utilizing fetch and randomuser.me?

I am currently working with the randomuser.me API and have set up the fetch request correctly. My goal is to retrieve 5 users separated by commas instead of just one. As mentioned in randomuser.me's documentation, I simply need to append the fetch UR ...

jQuery's find method returns a null value

During my Ajax POST request, I encountered an issue where I wanted to replace the current div with the one received from a successful Ajax call: var dom; var target; $.ajax({ type: "POST", url: "http://127.0.0.1/participants", data: "actio ...

The intricate field name of a TypeScript class

I have a TypeScript class that looks like this - export class News { title: string; snapshot: string; headerImage: string; } In my Angular service, I have a method that retrieves a list of news in the following way - private searchNews(sor ...

I am experiencing issues with my HTML select list not functioning properly when utilizing a POST service

When using Angularjs to automatically populate a list with *ngFor and then implementing a POST service, the list stops functioning properly and only displays the default option. <select id="descripSel" (change)="selectDescrip()" > <option >S ...

What steps should I take to create a plugin for a library if defining it as a peerDependency does not provide a specific implementation for me to work with?

Requirements for My Plugin: I'm currently in the process of developing a new plugin that is dependent on popularLibrary.js. Here are the key points about my plugin: It will not function properly if popularLibrary.js is missing. It is designed to wo ...

An issue with the Ajax login check is preventing the form from submitting successfully

I am seeking assistance with my ajax and javascript code. I have a login check implemented using ajax, based on the guidance provided in this answer: Check if user logged in on ajax page change. When the submit button is clicked, the function checks if the ...

Validating a field conditionally upon submission

Adding a required validation conditionally to the "imageString" field upon submission, but the expected required validation is not being set. Initializing the form. constructor(){ this.poeForm = this.fb.group({ imageString: [""], imageFileNam ...

Looking to handle a .csv file containing both quotes and commas within the quotes in Node.js - how can I achieve this

My code solution successfully parses a CSV file, but it doesn't handle cases where data has commas within quoted fields. For example, "not, accounted","normal". let filePath = Path.resolve(__dirname, `./MyData.csv`); let data = fs.readFileSyn ...

Unable to dynamically load images using webpack-image-loader and referenced in a JSON file

Currently, I am working on dynamically loading images from a JSON file using webpack-image-loader and React. Previously, I successfully used PNGs by placing the variable name in curly braces: import gratuita from 'images/gift-50.png'; <img ...

Tips for accessing elements other than the root element using this.$el

Within my template, the structure is as follows: <div v-show="showContent" class="content-block-body"> <div class="slider-pro"> <div class="sp-slides"> <slide v-for="block in subItems" ...