svelte: TypeScript Class Attributes Bug

Describe the bug

When defining a class with attributes within a <script context="module" lang="ts"> <script lang="ts"> tag, it doesn’t work. With JS however, it works fine. I couldn’t figure out why that is.

Reproduction

https://github.com/True-cc/TSClassSvelteIssue

In src/lib/, the JSThing.svelte works fine but the other two don’t.

Logs

5:23:02 PM [vite] Internal server error: Unexpected token
  Plugin: vite-plugin-svelte
  File: /mnt/data/Projects/TS/TSClassSvelteIssue/src/lib/TSThing.svelte
  1: <script context="module" lang="ts">export class Thing {
  2:     name;
             ^
  3:     constructor(name) {
  4:         this.name = name;
      at error (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:17700:19)
      at Parser$1.error (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:17776:9)
      at Parser$1.acorn_error (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:17770:14)
      at Object.read_script [as read] (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:8465:16)
      at tag (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:16859:33)
      at new Parser$1 (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:17735:21)
      at parse$3 (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:17867:20)
      at compile (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/svelte/compiler.mjs:31339:17)
      at compileSvelte2 (file:///mnt/data/Projects/TS/TSClassSvelteIssue/node_modules/@sveltejs/vite-plugin-svelte/dist/index.js:313:20)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

System Info

System:
    OS: Linux 5.14 Arch Linux
    CPU: (6) x64 Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
    Memory: 19.77 GB / 31.31 GB
    Container: Yes
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.11.1 - /usr/bin/node
    Yarn: 1.22.17 - /usr/bin/yarn
    npm: 8.1.2 - /usr/bin/npm
  Browsers:
    Chromium: 95.0.4638.69
    Firefox: 94.0
  npmPackages:
    svelte: ^3.37.0 => 3.44.1

Severity

blocking an upgrade

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 16
  • Comments: 17 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I also encountered this bug and can confirm that changing TypeScript’s target to es2021 resolved the problem for me.

tsconfig.json:

{
  "extends": "@tsconfig/svelte/tsconfig.json",
  "compilerOptions": {
    "target": "es2021",
    "useDefineForClassFields": true,
    "module": "esnext",
    "resolveJsonModule": true,
    "baseUrl": ".",
    /**
     * Typecheck JS in `.svelte` and `.js` files by default.
     * Disable checkJs if you'd like to use dynamic types in JS.
     * Note that setting allowJs false does not prevent the use
     * of JS in `.svelte` files.
     */
    "allowJs": true,
    "checkJs": true,
    "types":[
      "svelte",
      "vite/client"
    ]
  },
  "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
}

Yes found this one too. It’s reproducible directly in the REPL: https://svelte.dev/repl/5ee171d2febb4eff9c9110c9aad2dfc5?version=3.48.0

Just paste in the following:

<script lang="ts">
class TestingClass {
  private id = 0;
}
</script>
<h1>Hello world!</h1>

No context required. Actually, even a pure JS version will trip up the REPL. A TypeScript version with target es2020 seems to actually be a workaround – I guess it transforms into JS that doesn’t cause the issue. And it’s nothing to do with private (dropping it still fails).

This suggests the issue title might be misleading, as no TypeScript is needed to replicate this.

i.e., this also breaks, even in the REPL:

<script>
class TestingClass {
  id = 2;
}
</script>
<h1>Hello world!</h1>

Backtrace is as follows, which does suggest it’s a Svelte issue.

file: /Users/stuart/git/kc-chat-svelte/src/components/Survey.svelte:2:7
 1 |  <script lang="ts">class TestingClass {
 2 |      id = 0;
             ^
 3 |  }
 4 |  </script>
error during build:
ParseError: Unexpected token
    at error (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:17722:20)
    at Parser$1.error (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:17798:10)
    at Parser$1.acorn_error (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:17792:15)
    at Object.read_script [as read] (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:8688:17)
    at tag (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:16704:34)
    at new Parser$1 (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:17757:22)
    at parse$3 (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:17889:21)
    at compile (/Users/stuart/git/kc-chat-svelte/node_modules/svelte/compiler.js:32271:18)
    at compileSvelte2 (/Users/stuart/git/kc-chat-svelte/node_modules/@sveltejs/vite-plugin-svelte/dist/index.cjs:342:48)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

So, yes, strictly as a workaround, switching target to es2020 does resolve it, but it’s still there for simple JS.

This probably has something to do with the tsconfig esnext target. From typescript playground, it seems like with esnext target. typescript would preserve the class field instead of transforming it to a constructor initialized field, or Obeject.defineProperty. So this is not a typescript only problem. Your js example is not the same as the typescript version in this context.

es class field is rather new. I presume it’s just the acorn(parser) version we’re using does not support the class field.

esnext

class Thing {
  name;
}

no useDefineForClassField and es2021

export class Thing {
}

useDefineForClassField and es2021

export class Thing {
    constructor() {
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
    }
}

I can confirm this bug in latest versions of Svelte, find it here on this Stackblitz: https://stackblitz.com/edit/sveltejs-kit-template-default-5wo4f8?file=src/routes/+layout.svelte

(see src/routes/+layout.svelte)

I also want to mention, that changing the target to ES2020 sadly did nothing for me.

I was also having this problem using a target of ESNext, and changing it to ES2021 resolved the problem. If you’d like another way to reproduce the problem, this repo does it, with this file in particular producing an error.

@mckravchyk you can try setting your tsconfig to target es2021.

I’m experiencing something related. I tried to define a class within the static context and I get an unexpected token error at equals sign in class property.

<script context="module" lang="ts">
class TestClass {
  private test = true; // Unexpected token =
}
</script>

Edit: O, actually it’s not just in the context module, it’s within any script block. Seems like it’s a different issue.