Skip to content

Typescript interpretation / Compilation Errors #22212

Description

@michael-paulus-icev

Describe the bug

We are migrating from vite 5.2 to the latest version, while doing so, I had everything working until I went to run the app and some of our pages were broken. After doing some research, it appears that vite 5.2 was also broken, but not in all circumstances but vite 8.x is in all when using accessor and private constructor variables, the accessor is invoked before the constructor variable is set, which is different from how typescript compilation works.

Reproduction

N/A

Steps to reproduce

Code Sample that works on 5.2 but not on 8.x

class CoursesApi {
    onClearFilters() {

    }
}

class Hello {
    constructor(private input: { onRefresh: () => void, onClearFilters: () => void }) {

    }


    private api = new CoursesApi();

    accessor util = {
        onRefresh: this.input.onRefresh,
        onClearFilters: this.input.onClearFilters
    };

}

var hello = new Hello({ onRefresh: () => { }, onClearFilters: () => { } })

console.log(hello);

Code Sample 2 which doesn't work on 5.2 or 8.x

class Hello {
    constructor(private input: { onRefresh: () => void, onClearFilters: () => void }) {

    }


    accessor util = {
        onRefresh: this.input.onRefresh,
        onClearFilters: this.input.onClearFilters
    };

}

var hello = new Hello({ onRefresh: () => { }, onClearFilters: () => { } })

console.log(hello);

The problem with Code Sample 1 is that on vite 8.x it outputs like this:

var Hello = class {
	constructor(input) {
		this.input = input;
		this.api = new CoursesApi();
	}
	#A = {
		onRefresh: this.input.onRefresh,
		onClearFilters: this.api.onClearFilters
	};
	get util() {
		return this.#A;
	}
	set util(v) {
		this.#A = v;
	}
};

on 5.2 it outputs like this

class Hello {
  constructor(input) {
    __privateAdd(this, _A);
    this.input = input;
    this.api = new CoursesApi();
    __privateSet(this, _A, {
      onRefresh: this.input.onRefresh,
      onClearFilters: this.input.onClearFilters
    });
  }
  get util() {
    return __privateGet(this, _A);
  }
  set util(v) {
    __privateSet(this, _A, v);
  }

This doesn't access this.input until this.input is actually set.

For reference typescript compiles it like this:

class Hello {
    constructor(input) {
        this.input = input;
        this.api = new CoursesApi();
        _Hello_util_accessor_storage.set(this, {
            onRefresh: this.input.onRefresh,
            onClearFilters: this.input.onClearFilters
        });
    }
    get util() { return __classPrivateFieldGet(this, _Hello_util_accessor_storage, "f"); }
    set util(value) { __classPrivateFieldSet(this, _Hello_util_accessor_storage, value, "f"); }
}

If you remove the api = field on the class, then 5.2 and 8.x fail, because 5.2 then adds the creation of the method directly in __privateAdd instead of the Set method before input is set.

How do we get vite to output the code so that it sets this.input correctly before creating the object that uses it. I would say that is "Correct" becaus that is what the typescript compiler does.

System Info

System:
    OS: Windows 11 10.0.26100
    CPU: (16) x64 Intel(R) Core(TM) Ultra 9 285H
    Memory: 32.82 GB / 63.43 GB
  Binaries:
    Node: 25.3.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.22 - C:\Users\michael.paulus\AppData\Roaming\npm\yarn.CMD
    npm: 11.6.2 - C:\Program Files\nodejs\npm.CMD
    pnpm: 10.32.1 - C:\Users\michael.paulus\AppData\Roaming\npm\pnpm.CMD
  Browsers:
    Edge: Chromium (143.0.3650.139)

Used Package Manager

pnpm

Logs

No response

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug: upstreamBug in a dependency of Vitep3-minor-bugAn edge case that only affects very specific usage (priority)

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions