0

Is there a way to tell VSCode that an object is of a certain type so that code hinting and code intelligence work? I am using ES2015 I believe.

As an example, let's say I'm populating an array with specific objects:

var person = new Person();
var person2 = new Person();
var person3 = new Person();

var people = [person, person2, person3];

// later on - see second example

var person = people[0];

I don't think that VSCode knows what type of object this is.

I know I can use JSDoc hinting something like so:

/* {Person} */
var person = people[0];

But this looks out of place and unformatted when reading it back later.

Is there a way to tell VSCode the type of object any other way?

I have figured out one way but I don't like it:

var person = new Person();
person = people[0];

Update:
I'm actually defining the value on an HTML Option element and retrieving it later in the List change handler:

function createList() {
   // loop through items and add them as option
   {    
      var optionName = useListItem ? "li" : "option";
      var option = document.createElement(optionName);
      option.name = people[i].name;
      option.value = people[i]; // in the browser this is converted to a primitive but it remains an object in the environment i'm in
      myList.appendChild(option);
   }
}

function listChangeHandler() {
    var person = myList.value; // vscode does not know what this is
}
1.21 gigawatts
  • 16,517
  • 32
  • 123
  • 231
  • 2
    AFAIK, your only two options are to use JSDoc or TypeScript. Choose your poison. You could also create `.d.ts` type declarations if you don't want to do a full TypeScript migration. – Michael M. Jan 29 '23 at 00:49
  • Your code works fine out of the box with vscode intellisense. "I don't think that VSCode knows what type of object this is." - why do you think that? Typescript will also help here, but that's not directly related to your question. – Andy Ray Jan 29 '23 at 00:52
  • 1
    [^](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it#comment132824289_75271930) Yes, the compiler infers correctly based on your example. See in a JS playground (https://tsplay.dev/Na4Jpw) How have you configured your TypeScript environment in VS Code? Please update the question with your complete JSconfig or TSConfig, etc. – jsejcksn Jan 29 '23 at 00:56
  • 1
    Re: "_But this looks out of place and unformatted_": You can use inline type casting if that's preferable — see [this answer](https://stackoverflow.com/a/72325965/438273) – jsejcksn Jan 29 '23 at 00:57
  • @jsejcksn interesting. I didn't know you can do inline jsdocs – 1.21 gigawatts Jan 29 '23 at 01:28
  • @jsejcksn so the example is very simplified. i'm actually defining the variable as a list option value. see updated code above. and it is in another function that i retrieve it. – 1.21 gigawatts Jan 29 '23 at 01:30
  • [^](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it?noredirect=1#comment132824525_75271930) @1.21gigawatts I don’t see any updated code. – jsejcksn Jan 29 '23 at 01:33
  • @jsejcksn refresh – 1.21 gigawatts Jan 29 '23 at 01:39
  • 1
    @MichaelM. I would like to move over to Typescript but the project is large and I'm hesitant to make the move at this moment – 1.21 gigawatts Jan 29 '23 at 01:41
  • 1
    `option.value = people[i];` will result in `option.value` being the string `"[object Object]"`. DOM element attributes only accept strings. – LJᛃ Jan 29 '23 at 01:49
  • @LJᛃ Try it. For me I can assign objects to the value property. I'm not in the browser but a browser subset environment but I don't believe the browser enforces that. – 1.21 gigawatts Jan 29 '23 at 01:50
  • @1.21gigawatts no you can't, at least not with vanilla js in firefox or chrome. And that's probably why vscode won't detect your type, because in a normal environment your type will be `string`. – LJᛃ Jan 29 '23 at 01:53
  • @LJᛃ OK I just tested it in the browser and you're correct. In my environment it leaves it by reference. – 1.21 gigawatts Jan 29 '23 at 01:55
  • 2
    [The spec](https://html.spec.whatwg.org/multipage/form-elements.html#the-option-element) defines `value` (and all other attribute accessors) as equivalent primitive types (either strings or booleans) and browsers do enforce those. – LJᛃ Jan 29 '23 at 01:59
  • [^](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it#comment132824657_75271930) "_I'm not in the browser but a browser subset environment_": @1.21gigawatts This (and more) is why I [asked](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it#comment132824320_75271930) for you to update the question with your TS configuration information. The question still seems to lack critical detail. – jsejcksn Jan 29 '23 at 02:02
  • @jsejcksn I'm not using typescript at the moment because reasons. If I was using typescript I could type the object. – 1.21 gigawatts Jan 29 '23 at 02:06
  • 1
    [^](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it#comment132824759_75271930) @1.21gigawatts I understand your perspective, but I think you might have some misconceptions — all of the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) features in VS Code that you have described are provided by the TypeScript language service (even if you're just using JavaScript) — and if you have not configured it using one of the types of config files that I mentioned, then you are using the defaults. – jsejcksn Jan 29 '23 at 02:09
  • @jsejcksn if you say so. I believe that vscode does some intellisense without jsconfig.json or tsconfig.json. try it. create some classes and then instantiate them as variables and you'll see intellisense working providing properties and so on. – 1.21 gigawatts Jan 29 '23 at 02:11
  • 1
    [^](https://stackoverflow.com/questions/75271930/type-casting-an-object-in-javascript-to-tell-vscode-about-it#comment132824781_75271930) @1.21gigawatts Yes — that's an example of an environment which lacks configuration, so it uses the built-in compiler defaults. – jsejcksn Jan 29 '23 at 02:17
  • fwiw maybe you want to reconsider relying on non spec compliant, platform specific behavior in your code, if not for the intellisense, do it for future you or other developers looking at this code. – LJᛃ Jan 29 '23 at 02:23
  • @1.21gigawatts I think your current question is symptomatic of the [XY problem](https://meta.stackexchange.com/a/66378/150810). From what I read, it seems like you want to associate non-string data to ` – jsejcksn Jan 29 '23 at 02:28
  • @jsejcksn it is in this case but there are other cases where I'd like to simply cast a variable to a type. This is what I had before JS: `var foo = something as Person`. I'm trying to get back to that. I may just need to set a few days aside to convert to Typescript. – 1.21 gigawatts Jan 29 '23 at 03:21

1 Answers1

0

You clarified in a comment that you would like to associate non-string data with a series of <option> elements within a <select> element, and later retrieve that data based on the currently-selected option.

For associating arbitrary data with objects that are not owned (e.g. DOM elements), JavaScript offers the WeakMap. Read more at: What are the actual uses of ES6 WeakMap?

Here's an example of associating instances of a Person class to Option elements, and retrieving the associated Person depending on which one is selected. It demonstrates various JSDoc type-related syntax, including inline type casting:

JS code in TS Playground

class Person {
  /** @param {string} name */
  constructor (name) {
    this.name = name;
  }
}

/**
 * @param {Person} person
 * @returns {HTMLOptionElement}
 */
function createOption (person) {
  return new Option(person.name.slice(0, 1), person.name);
}

const select = /** @type {HTMLSelectElement} */(document.getElementById("person-select"));
const output = /** @type {HTMLSpanElement} */(document.getElementById("output"));

const personMap = /** @type {WeakMap<HTMLElement, Person>} */(new WeakMap());

const updateOutput = () => {
  const [option] = select.selectedOptions;
  output.textContent = personMap.get(option)?.name ?? "none";
};

const persons = [
  new Person("Austin"),
  new Person("Blake"),
  new Person("Charlie"),
];

for (const person of persons) {
  const option = createOption(person);
  personMap.set(option, person);
  select.appendChild(option);
}

select.addEventListener("change", updateOutput);
updateOutput();
body, select { font-family: sans-serif; font-size: 1rem; }
<div>Selected person: <span id="output"></span></div>
<select id="person-select"></select>
jsejcksn
  • 27,667
  • 4
  • 38
  • 62