TypeScript: VSCode analyses `import { sqlite3 } from "sqlite3"` differently, and wrongly, from any other import in JS mode.

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

Versions:

image

Problem:

image

the import is very clearly used, yet VSCode refuses to acknowledge it is. No matter how immediately I use it, VSCode keeps complaining:

image

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 19 (2 by maintainers)

Most upvoted comments

No, of course I don’t read the docs if they can only be read when you already know which settings.json key or “name of the feature” is involved. Documentation is only as good as it’s discoverable, which is super not the case here. If there is an expectation that people “read the docs” before they download and use VS Code, there is a wild mismatch between expectations and how people actually use VS Code.

Pick sane defaults, let users override those. Not the other way around. If there is no project with a package.json, then there is no typing to guess at, and no type guessing should happen until the type system can confirm that the library name in the source is the one that belongs to the type hints it knows about. Anything else is straight up bad (or lazy, but that is certainly not the case here, a lot of work has gone into VS Code, and I’m certainly not going to deny that) hinting.

TL;DR - all imports in JS files should have their ‘value’ bit set, because in this case we’re getting confused and thinking it’s a type-only import, which it can’t be, thus we’re missing the in-fact usage of sqlite3.

Please stop talking about node: this isn’t about node, this is about pure, spec-compliant JS analysis performed on string data without ever being saved to a real file and without ever running it. We’re not “installing sqlite3 in a dir using npm, and then creating a file that imports that and running it”: this issue is not about using sqlite3. To repeat: we are not using node, at all, anywhere, in this bug report. We’re just looking at a very clear case in which VS Code’s linting if the import statement makes it a yield a false claim about scoping.

So: we’re creating a new file, which we’re not saving, with the language mode set to Javascript, and we put in those two lines, and then we see VS Code flagging a scoping issue that (based on the JS specification) does not actually apply, where VS Code’s linter erroneously claims that the imported namespace is not in scope on the very next line. And we also only see it claim this when the importClause has a fromClause that uses the StringLliteral "sqlite3". As the code that VS Code is automatically linting for us is not part of any project, is not being run by anything, and isn’t even a file on disk (yet), the linting can only be looking at the actual string data it’s running on, without any assumptions on top of that: the "sqlite3" string does not “point” to anything: it’s just as meaningless as "hoalifghjlo3asi4hgf3wa" in the use-case that this issue is about.

Because, and this is the critical bit, VS Code cannot know what “sqlite3” is yet, since there is no project backing this file. There is no module installed anywhere, there is no dependency to consult, there is no hardcoded interface that is known to apply, there is no tech stack that’s going to run this file: as just a new file that hasn’t even been saved yet, the string "sqlite3" does not mean anything yet. So for the purpose of feedback on code quality and validity, VS Code should treat it as the meaningless string literal it is, the exact same way it treats any other string literal that we see it do when we change “sqlite3” to any other string literal.

In the use case for this issue, VS Code’s linting is generating an erroneous report to the user, with associated incorrect syntax highlightling as a result. Unless VS Code knows what the code is for (e.g. it’s in a dir that is clearly identifiable as a node project), it should not make any assumptions, or reach for any presets, based on the import’s string literal.

VS Code has a dedicates “typescript” filetype. Having automatic type acquisition kick in for those makes perfect sense. Having it kick in for files flagged as “javascript” instead of “typescript”, or any other not-typescript file, does not, so yeah: if I’m working in plain JS, VS code automatically grabbing sqlite3 type information for a project that doesn’t use that is still a bug and should be fixed.

If you don’t need Automatic Type Acquisition, disable it.

No, that’s a pretty ridiculous thing to suggest: this should be disabled for “not-TS” files, and if folks want it to kick in for non-TS, they should be able to enable that, not the other way around.

And what VSCode uses internally should be irrelevant for user-facing behaviour: if a user uses modern JS syntax to import a namespace from a module, VSCode should not misreport the scoping if the syntax is 100% correct and valid.

This is become more and more a case of “the devs not recognising their own needs are not the user’s needs”: if the code is valid, and the scoping, as per ES rules, is 100% correct, VS code should not report the wrong thing.

And it is reporting objectively the wrong thing for users in this case. What VS code wants to do internally is completely irrelevant for this use-case.

VS Code has a setting called “Disable Automatic Type Acquisition” (typescript.disableAutomaticTypeAcquisition).

TypeScript has an option section called typeAcquisition.

IMO, that is enough to close this issue.


I don’t understand the “bug” here.

all imports in JS files should have their ‘value’ bit set

we’re getting confused and thinking it’s a type-only import

Do you mean blindly regarding every imported identifier as valid, so that related linting together with type checking will never apply to JavaScript?

But I think a more reasonable behavior would be filtering definitions when in js files, as TypeScript interfaces cannot be imported by JavaScript or similar languages like Flow. Then,

import { sqlite3 } from "sqlite3";

should by default give:

Module '"sqlite3"' has no exported member 'sqlite3'. ts(2305)

Please check https://www.npmjs.com/package/sqlite3

If you're not using this package, please check your Type Acquisition options.

The discussion started from “unused variable checking”, a kind of linting, which involves semantics inference.

Syntactically correct thing is never supposed to be correct.

For example, the code below is perfectly correct in syntax, but totally wrong in semantics.

"use strict";

let o = Object.freeze(Object.create(null));
o.a = 2;

It will be parsed and executed smoothly, but will eventually throw a runtime error:

TypeError: Cannot add property, object is not extensible

Even worse, it will fail silently, if you remove the "use strict" statement.

Linting is recognizing pitfalls and showing suggestions to protect dev from creating things that make no sense at runtime.

From ESLint:

identifying and reporting on patterns found in code, with the goal of making code more consistent and avoiding bugs.


The semantics of imported identifiers exactly comes from module resolution.

VS Code somehow knows what sqlite3 is, even on a new file that has never been saved

AFAIK, VS Code (TypeScript) is asked to guess context by default when working on JavaScript. Here, it assumes "sqlite3" to be the popular package sqlite3.

You say the behavior is not desired:

VS Code makes assumptions about what the “sqlite3” module is when it shouldn’t, because in the absence of any information other than “this is JS code”

Why? Given that Automatic Type Acquisition is enabled.

it should not make any assumptions

If you don’t need Automatic Type Acquisition, disable it.

Unused variables is not a syntax problem, but a semantic problem. And that code is not semantically correct, as Node.JS reports runtime error.

However, I agree that there is space for improvement. The error message should indicate that you are importing the wrong thing, instead of saying the import is unused.

You did import it in a wrong way.

According to the type definition, the named export called splite3 is an interface, that means it’s not a concrete thing in JavaScript. Interfaces only exist in compile time, and only in TypeScript. However, you are importing it in a JavaScript file, which is meaningless! It’s reported as unused because you can’t use something that doesn’t exist!

The correct way is:

import { DataBase } from "sqlite3";
new DataBase(...);
// or
import * as sqlite3 from "sqlite3";
new sqlite3.DataBase(...);

I recommend you to turn on checkJs in tsconfig.json. Then it will report an error as follows and help you find the problem:

‘sqlite3’ only refers to a type, but is being used as a value here. ts(2693)


By the way, the reason why VS Code reports on sqlite3 but not sqlite4 (even in a new file) is that definition files are cached. Hover over your import statement to see where the definition file is from. If you delete that file, the error will be hidden.

There is no dedicated example here, just open VSCode, type import { sqlite3 } from "sqlite3"; sqlite3.doAThing(); and set the file to javascript. Done: it immediately shows off this problem where it claims that the import is never used, despite literally being used on the next line.

Change sqlite3 into anything else and it works correctly (sqlite2, sqlitex, pigeon, it doesn’t matter), VSCode specifically does something wrong specifically for the word sqlite3.