Fix grammar checks for modifiers on @template type parameters#4077
Closed
Copilot wants to merge 3 commits into
Closed
Fix grammar checks for modifiers on @template type parameters#4077Copilot wants to merge 3 commits into
@template type parameters#4077Copilot wants to merge 3 commits into
Conversation
Port the logic from TypeScript's checker to properly resolve the parent declaration for type parameters defined in JSDoc @template tags. For the `const` modifier, resolve the effective JSDoc host to allow const type parameters on function/method/class declarations annotated via JSDoc. For the `in`/`out` modifiers, resolve the effective JSDoc host or find a @typedef tag in the same JSDoc block to allow variance annotations on type parameters of type aliases defined via @typedef. Also fix: - isJSDocTypedefTag to actually check the node kind - Use IsTypeOrJSTypeAliasDeclaration instead of IsTypeAliasDeclaration to properly handle reparsed JSTypeAliasDeclaration nodes Fixes #1299 Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix unexpected errors for modifiers on @template type parameters
Fix grammar checks for modifiers on May 29, 2026
@template type parameters
DanielRosenwasser
requested changes
May 30, 2026
Member
DanielRosenwasser
left a comment
There was a problem hiding this comment.
(Un)surprisingly, it seems like we have no tests for in/out modifiers when @template parameters are used on classes (maybe we had coverage for function-declared classes a while back).
Since we are now fiddling with logic to find host nodes, we need to make sure we don't regress.
Let's add a compiler test for this
// @checkJs: true
// @Filename: /index.js
/** @template in T */
export class Consumer {
/** @param {T} value */
eat(value) {
}
}
export class Food {
/** @readonly */ isFood = true;
}
export class Vegetable extends Food {
/** @readonly */ isVegetables = true;
}
export class Meat extends Food {
/** @readonly */ isMeat = true;
}
/** @param {Consumer<Food>} omnivore */
export function feed(omnivore) {
omnivore.eat(new Meat());
}
/** @type {Consumer<Vegetable>} */
let vegetarian = new Consumer();
feed(vegetarian);Also, this test which validates calculation of in/out
/** @template in T */
export class Producer {
make(): T {
throw new Error("Not implemented");
}
}
/** @template in out T */
export class Consumer {
/** @param {T} value */
take = (value) => {}
}
ahejlsberg
reviewed
May 30, 2026
Member
There was a problem hiding this comment.
The changes in this PR are overly complicated. With reparsing there's no reason to look for JSDoc hosts and walk around in the AST. All we need is to permit JSTypeAliasDeclaration parents for type parameters when checking in and out modifiers. I will put up a simpler PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Grammar checks for
in/out/constmodifiers on type parameters in JSDoc@templatetags were not resolving the effective parent declaration, causing spurious TS1274 errors like:Changes
constmodifier — when a type parameter is inside a@templatetag, look up the effective host declaration (function/class) instead of using the template tag as the parent@typedefforin/outmodifiers — same as above, with fallback to finding a@typedeftag in the same JSDoc block (which acts as a type alias)isJSDocTypedefTag— was unconditionally returningfalse(stubbed with// !!!)IsTypeOrJSTypeAliasDeclaration— the existing check usedIsTypeAliasDeclarationwhich doesn't matchKindJSTypeAliasDeclaration(the reparsed typedef nodes)