-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Add a code fixer for --isolatedDeclarations errors #58260
Conversation
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
Looks like you're introducing a change to the public API surface area. If this includes breaking changes, please document them on our wiki's API Breaking Changes page. Also, please make sure @DanielRosenwasser and @RyanCavanaugh are aware of the changes, just as a heads up. |
This code fixer fixes the following patterns. 1. Adding missing types on places that type can be explicitly annotated 2. Adding satisfies with type assertion on a value. 3. Create a namespace for expando functions and declare the property on the namespace. 4. Factor out expressions in heritage clauses (class B extends <expression>) and give them separate names. Signed-off-by: Hana Joo <hanajoo@google.com>
Seems like this may need a rebase now that the base PR is in. |
12869dd
to
4e506f9
Compare
@microsoft-github-policy-service agree company="Google" |
709e3fc
to
c9698a3
Compare
I'm still going through the test cases, but one thing I'm not seeing are test cases for decorated classes/functions/etc. Even if that's not implemented yet, it may be worth adding some just to make sure they are covered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just finishing up reading the tests; I think overall I wonder if we need to be this complete, e.g. if it's worth handling cases like mixins, destructurings, and so on, which have very complicated conversions.
index: 0, | ||
newFileContent: | ||
`function foo() {return 42;} | ||
export const g = function (): number { return foo(); };`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we've added support for function expressions in initializers, right? So this isn't yet valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we did add support for these AFAIK, this isn't an error under --isolatedDeclarations (I test it and it confirms that it isn't) . It errors by first looking at the variable, if there's no type annotation - goes into the initializer and sees if it's a function type and check all places have appropriate type annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I guess I was going off of the list of unfinished things including initializers with functions...
// @isolatedDeclarations: true | ||
// @declaration: true | ||
// @lib: es2019 | ||
//// export const a = Symbol(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point we really have to figure out how to make symbol inference better; I think we're blocked by the freshness problem I failed to resolve.
tests/cases/fourslash/codeFixMissingTypeAnnotationOnExports21-params-and-return.ts
Show resolved
Hide resolved
tests/cases/fourslash/codeFixMissingTypeAnnotationOnExports23-heritage-formatting.ts
Show resolved
Hide resolved
tests/cases/fourslash/codeFixMissingTypeAnnotationOnExports30-inline-import.ts
Show resolved
Hide resolved
tests/cases/fourslash/codeFixMissingTypeAnnotationOnExports32-inline-short-hand.ts
Show resolved
Hide resolved
tests/cases/fourslash/codeFixMissingTypeAnnotationOnExports36-conditional-releative.ts
Show resolved
Hide resolved
Is it expected for this PR to be sufficient to work with Quick Fixes in VSCode, or with ts-fix? I've tried both with this branch and was not able to see any fix suggestions despite successfully getting isolatedDeclarations errors. |
Good point, I tested this once with a locally built tsd, but I can't reproduce the result with the current state. We intend to support this in vscode as a quick fix and anywhere that uses tsd. Thank you for bringing this up, I'll try to figure out why this isn't working and fix it before merge. |
Theoretically ts-fix should "just work", so that's definitely odd. |
Actually, I'm seeing the code fixes. I'm doing development on a cloud machine so I'm using a browser to access vscode in my cloud machine, but it seems to work when I'm running this locally (through a remote desktop in the cloud machine). I don't understand why the difference 🤷🏻 , but it at least seems to work. |
such as "A"|"B" --> string in case the d.ts emitter widens it. Also expose 'getWidenedLiteralType' as an internal API for the fixer to be able to imitate what the type checker is doing.
Added test cases for experimental / non-experimental decorators, I think nothing should be affected as the decorators shoudn't change the types. It seems to work well from what I can see. |
…expressions Widening of types only work on types from variable declaration, so when getWidenedLiteralType is being called on expressions the compiler wouldn't widen it. So call getWidenedLiteralType on the type of variables instead on those cases.
be5529d
to
cb45ffe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the whole, this seems fine to me; I think we can get feedback on this early and see if people find the big literal ones "too much" or not. But, I'm guessing we won't end up with much feedback until the actual release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of nits, overall I think the implementation looks really good.
} | ||
interface InferenceResult { | ||
typeNode?: TypeNode | undefined; | ||
mutatedTarget: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks spooky to me 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming you're talking about the naming or would it be the logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the strategy of having functions that conditionally mutate something and have to communicate whether they've done so... I didn't study it enough to fully understand why that was needed. Not necessarily a blocker, just a little eyebrow-raising
Some feedback after trying the code fixer out on part of our codebase. Unexpected:
Bug:
|
Yeah, ts-fix itself has some problems that extend past just trying to use it with this PR; if you can figure out a fix that would of course be awesome to take over there, but it's definitely not a finished codebase. |
and reuse it. Remove suggestVariableName as this adds very little value compared to the code size it had.
Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
…de fixes for them
...program.getSemanticDiagnostics(sourceFile, cancellationToken), | ||
...program.getSyntacticDiagnostics(sourceFile, cancellationToken), | ||
...computeSuggestionDiagnostics(sourceFile, program, cancellationToken), | ||
]; | ||
if (getEmitDeclarations(program.getCompilerOptions())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If currently we are supporting providing code fix for errors only when --isolatedDeclarations
is turned on may be should get declaration diagnostics only if its on to avoid perf hit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had them change to this in #58260 (comment), though; in the editor, we'll have already called this for diags, and it's cached.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can flip it back to just isolatedDeclarations if you think it'll be a problem, but it seemed less error prone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting Jake from the other comment
Actually, now that I think about it, this should probably just be getEmitDeclarations(program.getCompilerOptions()). It's possible that we could have quick fixes for declaration errors that are not in isolated declarations. And this call is cached so should be available for free anyway in codebases with declaration mode enabled.
Would you agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, my comment was slightly late 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache does help a little but not whole lot since every edit will have to throw out the errors and recalculate them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, we call this function already and offer them up as diagnostics in the editor; won't the cost already have been paid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes i forgot about the part where LS.getSemanticDiagnostics gets declaration diagnostics as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for posterity:
function getSemanticDiagnostics(fileName: string): Diagnostic[] {
synchronizeHostData();
const targetSourceFile = getValidSourceFile(fileName);
// Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file.
// Therefore only get diagnostics for given file.
const semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile, cancellationToken);
if (!getEmitDeclarations(program.getCompilerOptions())) {
return semanticDiagnostics.slice();
}
// If '-d' is enabled, check for emitter error. One example of emitter error is export class implements non-export interface
const declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile, cancellationToken);
return [...semanticDiagnostics, ...declarationDiagnostics];
}
I think all that's left for me is to just do the final format of the PR (one out of place import). Any other concerns? |
Just FYI, the |
Add a code-fixer to fix type errors for --isolatedDeclarations
This is built on top of the errors added in PR #58201.
This code fixer fixes the following patterns.
1. Adding missing types in places that type can be explicitly annotated.
2. Adding satisfies with type assertion on a value.
3. Create a namespace for expando functions and declare the property on the namespace.
4. Factor out expressions in heritage clauses (class B extends ), give them separate names and export them.