sveltejs/language-tools

TS: Named export from module script not recognized

IgnusG opened this issue · 8 comments

Describe the bug
Importing named exports from <script context='module'> returns an error saying:

Module '"*.svelte"' has no exported member ...

image

The image is from a test file that imports both the component and the helper method

The svelte component looks like this:

<script context="module" lang="ts">
export const reverseValue = (min: number, max: number) => (
  scale: number,
): number => max - scale + min;
</script>

...
Typescript Config
{
  "extends": "@tsconfig/svelte/tsconfig.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {"*": ["*", "typings/*"]},
    "noImplicitAny": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "noImplicitReturns": true,
    "noUnusedParameters": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "types": ["jest", "chrome", "node"],
    "allowJs": true,
    "isolatedModules": false,
    "target": "ESNext",
    "allowSyntheticDefaultImports": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/.svelte", "typings/*.d.ts", "test/*.ts"],
  "exclude": ["node_modules"]
}
  • Svelte: 3.24.1
  • Svelte Preprocess: 4.2.1
  • Svelte TS Config: 1.0.10
  • Typescript: 4.0.2

Expected behavior
The exports should be recognized

Severity
Not severe. Just a small hindrance

I'm not sure if we can solve this. The problem is that the Typescript Language Service does not know how to deal with Svelte files. There's just a minimal type definition in svelte that says "everything that ends with .svelte has a default export of type SvelteComponent". Even writing a TypeScript-Plugin will not help much because those are not used during running the compiler with the tsc command.
As a workaround you can just ignore the error by adding @ts-ignore in the line above the import.

If this is going to be kept open, should it be transferred to the language-tools repo?

As a workaround you can just ignore the error by adding @ts-ignore in the line above the import.

Yeah, I'm currently using // @ts-expect-error to remove the error

Another solution (not at all clean though) might be to automatically generate .d.ts files while building/linting/testing which include the declarations of the svelte component?

I've used a similar approach with a custom css module setup in one of my projects. This would get rid of the error during compile/linting/testing.

I've coupled it with a typescript plugin which then tricked the editor into recognizing the css classes as exports and allowed completion/linting during development even before the d.ts files were generated (of course as you've mentioned the plugin would only support the editor - tsc would need to rely on the generated declarations).

That's an interesting solution! Would you like to share your plugin code? I did not setup a TS plugin before, but thought about setting one up for Svelte before and having kind of a blue print would certainly help.

I'm actually using this awesome plugin by @mrmckeb https://github.com/mrmckeb/typescript-plugin-css-modules :)
It works very well at least within VS Code.

For the compilation step maybe it could be possible to add an option to the typescript preprocessor for svelte-preprocess to generate the declaration for every svelte component while running. If I a tool uses svelte-preprocess it would then immediately get the correct typings

https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin

Seems like angular language service use the plugin technique. We could probably learn something from their code 😂.

I'm not sure you want to learn from my code haha, but if you have any questions I'll do my best to answer. Thanks for the shout-out @IgnusG.

The only note I'll make is that Language Service plugins only run in IDEs, not during build-time. People have been asking for this change for a while, but the TypeScript team don't seem convinced that it's a good direction.

There exists a TypeScript plugin now which comes packaged with the VS Code extension and which you need to enable through the settings. It also is available standalone as a npm package if you need to use it outside of VS Code.
The plugin fixes this issue.