Skip to content
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

Curious type checking behavior of Object.<string, *> typedefs with named properties in JSDoc (for TS checks on JS code). Is it a bug? #55668

Closed
spillz opened this issue Sep 7, 2023 · 3 comments

Comments

@spillz
Copy link

spillz commented Sep 7, 2023

πŸ”Ž Search Terms

Object.<string, *> JSDoc typedefs @Property

πŸ•— Version & Regression Information

  • I tested in the playground with recent versions, which all produce the same result

⏯ Playground Link

https://www.typescriptlang.org/play?ts=4.2.3&filetype=js#code/PTACBcGcFoGMAsCmsDWAoYAqTaAEncIBPAB0QBNEAzXAbwHkAjAK2XADoAeScAJwEsAdgHMANPgB8AX1wAFRL0gB7QQEM8BUCV5KyvcETo8BImWoC2iDYW26FBuoICu5xgpmrhV-MDQZs1gDivIiIULiquHrKguzW1lqqvKrmdPKKKqoy0Sq40LgAKkhRCjG44Eq4wiFhcfiEIeBOvIKQRnxCwjIAglU14J24lpCQnoh1mL5UToKwA7nVoeCqABQ5ggCUdHi4jc2CuAAGABKIADZnSuIAJLTr7BaIUgCEuACaSk4RIbi392MyIiIJJtJRncjsQ4AbjQUj8GGAAGFmiFBOAzoZVBdcEoaOBiqpGEoAG6Ib5k4lY-jkXCwJSUABcfhAAFEABqyFmIgosgAiDNwAGV4J9wbg3LghJSztTafSyQB3JAHEiqEaDVQHJSwWBOVXzA5CCIHTUqIjmT6glhscqVfFk6azA1oRZhVa0R4MgDkACklIgveIxgyAEwAVnE2t1+v4Km95iECi9Ug2CPZnO5fIFwtFNIl0tldMouEQpIO+M+wngOJ1etUBslbUESnAUSSrdx5WKQnACioqlgZLcsFUTkgZP4rf4bUoVETNKNmpx1rmuDninAaDOYVwzH9kQAvI4UohvX6A0GvKGIzXo-XY4J44neMmXf1VnvgRsYWmOVyefyuAAEIttWkAik4YoSlKVI0kWQ7IKO44RF4uDSk4E5tAqOgiOUpBWK6ywrB6J7egAMkQgiCGE4C9oGKGnl6bL0VGdYGk+1EvimW47hiVGHseljkZR1G0ReDHesxka1jGcZegmnGvoRqx8Wo35oEAA

πŸ’» Code

//@ts-check
/**
 * @typedef {Object.<string, *>} Persona
 * @property {string} name
 * @property {number} age
 */

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


//Currently all of the above are valid code:

//EXPECTED: Should be invalid code when passing an occupation in an anonymous object to the function
greeta({name:'Joe', age:25, occupation:'miner'})
//EXPECTED: Should be valid code even though occupation is not part of the interface because it is defined in an object first
let joea = {name:'Joe', age:25, occupation:'miner'}
greeta(joea);

//EXPECTED: Both should be invalid code because age value is wrong type
greeta({name:'Lynnettte', age:'X', occupation:'miner'})
let lynna = {name:'Lynnette', age:'X', occupation:'miner'}
greeta(lynna);

πŸ™ Actual behavior

No errors appear in the TypeScript checker/compiler because it appears the Object.<string, *> declaration overrides the property declarations and allows any types for those named properties.

3 of the 4 calls should produce a type error if we are following the TypeScript convention that would apply to what I suppose would be the equivalent TypeScript type:

export declare type Persona = {
    name: string,
    age: number,
    [key:string]:any,
}

πŸ™‚ Expected behavior

//EXPECTED: Should be invalid code when passing an occupation in an anonymous object to the function
greeta({name:'Joe', age:25, occupation:'miner'})
//EXPECTED: Should be valid code even though occupation is not part of the interface because it is defined in an object first
let joea = {name:'Joe', age:25, occupation:'miner'}
greeta(joea);

//EXPECTED: Both should be invalid code because age value is wrong type
greeta({name:'Lynnettte', age:'X', occupation:'miner'})
let lynna = {name:'Lynnette', age:'X', occupation:'miner'}
greeta(lynna);

Additional information about the issue

No response

@spillz spillz changed the title Curious type checking behavior of Object.<string, *> typedefs with named properties in JSDoc. Is it a bug? Curious type checking behavior of Object.<string, *> typedefs with named properties in JSDoc (for TS checks on JS code). Is it a bug? Sep 7, 2023
@fatcerberus
Copy link

fatcerberus commented Sep 7, 2023

I believe this typedef is more or less equivalent to Record<string, any> & { name: string, age: number } which isn't well-behaved even in native TypeScript. See #17867

@spillz
Copy link
Author

spillz commented Sep 7, 2023

Ah, OK, that makes some sense then.

And after playing around a bit more I see that

/**
 * @typedef {Object} Persona
 * @property {string} name
 * @property {number} age
 */

will actually reproduce the correct behavior I was looking for, although it's unituitive that the absence of the <string, *> would do that. But what I'd also like is something that can reproduce the TypeScript that would allow the calls in the original JS code with occupation to pass type checks but flag the mis-typed age calls:

export declare type Persona = {
    name: string,
    age: number,
    [key:string]:any,
}

Is the only way to do that in JSDoc currently to use an import?

@spillz
Copy link
Author

spillz commented Sep 9, 2023

I'm closing this. It turns out the JSDoc typedef I wanted was very simply defined using TypeScript syntax:

//@ts-check
/**
 * @typedef {{name:string, age:number, [id:string]:any}} Persona
 */

@spillz spillz closed this as completed Sep 9, 2023
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