-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Plain JS binder errors #46816
Plain JS binder errors #46816
Conversation
Issue select errors from the binder in JS files that do not have checkJS explicitly turned on or off. These errors mirror runtime checks done by Javascript.
@mjbvz You might also have opinions about the appropriateness of these errors. |
My 2 cents is to just make it a suggestion diagnostic - don't go too crazy with when and how to report this in JS, or modifying how it surfaces in TS. |
@typescript-bot test this |
Heya @DanielRosenwasser, I've started to run the extended test suite on this PR at 9c85b4b. You can monitor the build here. |
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.
Seems sensible.
@typescript-bot pack this |
Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 9c85b4b. You can monitor the build here. |
@typescript-bot pack this |
I'm going to hold this until we have a chance to discuss this in the editor meeting tomorrow. |
const isCheckJs = isJs && isCheckJsEnabledForFile(sourceFile, options); | ||
const isPlainJs = isJs && !sourceFile.checkJsDirective && options.checkJs === undefined; |
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.
What’s the difference between isCheckJsEnabledForFile
the property checks you’re doing for isPlainJs
?
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 almost inlined that function to make this easier to read, except that it's used everywhere. isCheckJsEnabledForFile
is true whenever checkJs is explicitly true, whether locally or globally. To put it in the most parallel form:
sourceFile.checkJsDirective?.enabled || options.checkJs === true
vs
sourceFile.checkJsDirective === undefined && options.checkJs === undefined
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.
Ah, so the third kind of JS is JS where checkJs
is explicitly disabled?
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.
That's right. // @ts-nocheck
is the local form of that.
// - check JS: .js files with either // ts-check or checkJs: true | ||
// - external: files that are added by plugins | ||
const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX | ||
|| sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred); |
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.
isPlainJs || isCheckJs || ...
Related to my other question, but what other kind of JS is there?
It took me a second to realize, it’s easier to think about this condition in terms of what it excludes, although it may or may not be easier to write it that way:
// @ts-nocheck
files- JSON files
- ???
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.
- plain JS (no check options anywhere)
- checked JS (check turned on locally or globally)
- no-checked JS (check turned off locally)
- TS
- no-checked TS (check turned off locally)
- external (from plugins?)
- deferred (??)
- ???
I have no idea what's in ???, that's the problem with inverting the predicate.
src/compiler/program.ts
Outdated
const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX | ||
|| sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred); | ||
let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray; | ||
let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray; |
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.
try out some minified or otherwise compiled JS files to make sure perf doesn't tank or crash.
(Code uses line length to disable certain features)
Checker errors require requesting diagnostics, which stll needs to be peformance tested. This commit removes one cross-file duplicate declaration error in the tests.
On a desktop with tsserver logging enabled [1], I created a simple project, then opened a new Typescript file and pasted in some code [2].
Based on this:
[1] So, faster because it's a desktop; slower because logging is on. export class C {
set x(...n) { }
}
declare var x: Promise<number>
await x
const y = await x
class Test {
foo() {
}
bar() {
this.blargh(this, "completely wrong") // Can't autocomplete second parameter
const t = new Test()
this.blargh(t, "bar"); // Second parameter autocompletes to "foo", "blargh", "bar"
}
blargh<T>(a: T, k: keyof T) {
// some implementation
}
}
const t = new Test()
t.blargh(t, "bar")
t.blargh(t, "hi") |
@sandersn How long did it take for GTD to become usable without the diagnostics? (Sorry if I just missed that in your write-up.) If we think we might have to roll this back (contextually?), would it be useful to have a configuration option so that editors can add an escape hatch? |
Good question. After opening ajv.min.js, a lot less than a second. After opening run.js, around 2 seconds -- there probably was a difference from the semantics-requesting version, but not one that I could measure without a stopwatch. |
How do you expect most JavaScript users, who don't opt into nightly/beta versions of TypeScript in their editor, to provide feedback during the beta period? |
I think @andrewbranch looked into ways to monitor completion performance via telemetry when he was working on auto-imports. Maybe that would help? |
Now that I think about it, @mjbvz Can you confirm how much getSuggestionDiagnostics is called on plain JS files compared to getDiagnostics on TS files? I poked around vscode's typescript code but couldn't figure it out. From usage, it seems like suggestions show up on plain JS files at the same rate that errors do on TS files. |
@sandersn VS Code uses the |
Pretty much--I want to know whether it's calling |
Yes we should have the same code path for both JS and TS on the VS Code side |
* Plain JS binder errors Issue select errors from the binder in JS files that do not have checkJS explicitly turned on or off. These errors mirror runtime checks done by Javascript. * Rest of plain JS binder errors * address PR comments * Only issue binder errors in plain JS. Checker errors require requesting diagnostics, which stll needs to be peformance tested. This commit removes one cross-file duplicate declaration error in the tests. * fix const lint
Issue some errors from the binder in JS files that do not have checkJS explicitly turned on or off. These errors mirror runtime checks done by Javascript. The checker has many more errors that also cover runtime checks. I'll start on those next.
There are a few errors in the binder that don't have matching runtime errors: they nearly always indicate incorrect code, but not always.
A label is not allowed here
I decided to include "A label is not allowed here" because, even though it's not a runtime error on its own, if you use the label it will not be defined, which is a runtime error, and because the compiler error for the undefined label is so bad.
An object literal cannot have multiple properties with the same name in strict mode
I decided not to include this error, since it's not a runtime error in ES2015 and above according to an SO answer I found. It's a useful error for TS, though; probably the error message should be changed to read "An object literal should not have multiple properties with the same name.", or else it should be restricted to ES5-only. I filed #46815 to track that.
Addresses but does not fully fix #45349.