Skip to content

Referencing a JSDoc @interface declaration in @param declaration produces an unexpected error flag (JavaScript with TS checks) #55652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spillz opened this issue Sep 6, 2023 · 2 comments

Comments

@spillz
Copy link

spillz commented Sep 6, 2023

Does this issue occur when all extensions are disabled?: Yes

Steps to Reproduce:

Here's some sample JavaScript code

//@ts-check

/**
 * @interface Person
 * @property {string} name - The person's name.
 * @property {number} age - The person's age.
 */

/**
 * Greets a person.
 * 
 * @param {Person} person - The person to greet. //VS Code flags this as an error "Cannot find name 'Person'"
 * @returns {string} A greeting message.
 */
function greet(person) {
  return `Hello, ${person.name}! You are ${person.age} years old.`;
}

//Should be a valid call even though occupation is not part of the interface
greet({name:'Joe', age:25, occupation:'miner'});
//Should be an invalid call because age value is wrong type
greet({name:'Joe', age:'X', occupation:'miner'});

I would expect VS Code would flag the second invocation of greet as an error. Instead VS code flags the @param declaration as an error and allows both invocations of greet. Is this expected behavior or an upstream issue? From my reading of various JSDoc discussions, it seems that @interface isn't well supported across the entire ecosystem.

Failing that is the only way to achieve something like this where I can add arbitrary properties to an object as a function parameter that expects the object to have certain properties to use a .d.ts file with the interface definition and include that definition into my JSDoc?

@spillz spillz changed the title Referencing a JSDoc @interface declaration in @param declaration produces an unexpected error flag Referencing a JSDoc @interface declaration in @param declaration produces an unexpected error flag (JavaScript with TS checks) Sep 6, 2023
@mjbvz mjbvz transferred this issue from microsoft/vscode Sep 6, 2023
@mjbvz mjbvz removed their assignment Sep 6, 2023
@mjbvz
Copy link
Contributor

mjbvz commented Sep 6, 2023

Looks like a duplicate of #41675

@mjbvz mjbvz closed this as completed Sep 6, 2023
@spillz
Copy link
Author

spillz commented Sep 9, 2023

Just for posterity, it's possible to achieve what I need with a typedef rather than an interface. First, if we define the Person as a standard JSdoc @typedef, we can pass extra properties in the object provided it is defined as a named object.

//@ts-check

/**
 * @typedef Person
 * @param {string} name
 * @param {number} age
 */

/**
 * Greets a person.
 * 
 * @param {Person} person - The person to greet.
 * @returns {string} A greeting message.
 */
function greet(person) {
  return `Hello, ${person.name}! You are ${person.age} years old.`;
}

//This is an error because you can't have extraneous properties when passing anonymous objects
greet({name:'Joe', age:25, occupation:'miner'});

//But you can pass a named object with extra properties to the function, so this is OK
let joeObj = {name:'Joe', age:25, occupation:'miner'};
greet(joeObj);

//And this will be invalid because age is the wrong type:
let joeObj2 = {name:'Joe', age:'X', occupation:'miner'};
greet(joeObj2);

But we can go one step better and use a TypeScript type in the JSDoc @typedef with an extra key for arbitrary types and then pass extra properties in the call on the anonymous object as well:

//@ts-check

/**
 * @typedef {{name:string, age:number, [id:string]:any}} Person
 */

/**
 * Greets a person.
 * 
 * @param {Person} person - The person to greet. 
 * @returns {string} A greeting message.
 */
function greet(person) {
  return `Hello, ${person.name}! You are ${person.age} years old.`;
}

//This now works
greet({name:'Joe', age:25, occupation:'miner'});

//And this does not because age is the wrong type
greet({name:'Joe', age:'X', occupation:'miner'});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants