classes are not bad per-se but the syntax being inspired by java is terrible, major downside is that you cannot have an async constructor and you are forced to use a custom static create function and you have to prevent people to directly use the constructor. They also play bad with typescript if you want to pass an object as param and then Object.assign(this, obj) in the constructor. I don't understand why svelte cannot auto generate getter and setter in case you return an object where one of the property is a state like: function createCount() { const count = $state(0); return { count // svelte could auto generate get/set and we can avoid classes } }
Why do you think you need an async constructor? Not sure if I understand your 2nd reason but does this work for your needs? constructor(params: Partial) { Object.assign(this, params) }
@@yuqii65535 it can be for any reason, maybe the constructor needs to fetch, maybe it just depends on another function that is already async, maybe you need to promisify an event based api (see solutions that involve using img or video elements built at runtime to extract some info from the assets). your code does work in JS, but it will provide no type inference for the class, typescript will think that your class is empty and all the properties of Foo are lost and if you try to use "implement Foo" it will complain that you are not initialized all Foo properties. Moreover it doesn't work with svelte $state because it needs to be used in the class fields above the constructor. There's only 1 idiomatic way to define the properties of a class, their types and define the arguments of a constructor all at the same time: using public/private in the constructor argument. But this is not applicable for objects (aka named arguments).
@yuqii65535 it can be for any reason, maybe the constructor needs to fetch, maybe it just depends on another function that is already async, maybe you need to promisify an event based api (see solutions that involve using img or video elements built at runtime to extract some info from the assets). your code does work in JS, but it will provide no type inference for the class, typescript will think that your class is empty and all the properties of Foo are lost and if you try to use "implement Foo" it will complain that you are not initialized all Foo properties. Moreover it doesn't work with svelte $state because it needs to be used in the class fields above the constructor. There's only 1 idiomatic way to define the properties of a class, their types and define the arguments of a constructor all at the same time: using public/private in the constructor argument. But this is not applicable for objects (aka named arguments).
classes are not bad per-se but the syntax being inspired by java is terrible, major downside is that you cannot have an async constructor and you are forced to use a custom static create function and you have to prevent people to directly use the constructor. They also play bad with typescript if you want to pass an object as param and then Object.assign(this, obj) in the constructor.
I don't understand why svelte cannot auto generate getter and setter in case you return an object where one of the property is a state like:
function createCount() {
const count = $state(0);
return {
count // svelte could auto generate get/set and we can avoid classes
}
}
Why do you think you need an async constructor?
Not sure if I understand your 2nd reason but does this work for your needs?
constructor(params: Partial) {
Object.assign(this, params)
}
@@yuqii65535 it can be for any reason, maybe the constructor needs to fetch, maybe it just depends on another function that is already async, maybe you need to promisify an event based api (see solutions that involve using img or video elements built at runtime to extract some info from the assets).
your code does work in JS, but it will provide no type inference for the class, typescript will think that your class is empty and all the properties of Foo are lost and if you try to use "implement Foo" it will complain that you are not initialized all Foo properties.
Moreover it doesn't work with svelte $state because it needs to be used in the class fields above the constructor.
There's only 1 idiomatic way to define the properties of a class, their types and define the arguments of a constructor all at the same time: using public/private in the constructor argument. But this is not applicable for objects (aka named arguments).
@yuqii65535 it can be for any reason, maybe the constructor needs to fetch, maybe it just depends on another function that is already async, maybe you need to promisify an event based api (see solutions that involve using img or video elements built at runtime to extract some info from the assets).
your code does work in JS, but it will provide no type inference for the class, typescript will think that your class is empty and all the properties of Foo are lost and if you try to use "implement Foo" it will complain that you are not initialized all Foo properties.
Moreover it doesn't work with svelte $state because it needs to be used in the class fields above the constructor.
There's only 1 idiomatic way to define the properties of a class, their types and define the arguments of a constructor all at the same time: using public/private in the constructor argument. But this is not applicable for objects (aka named arguments).
@@Lemmy4555
1)
export class Foo {
constructor(url: string) {
this.#ready = this.#init(url)
}
async #init(url: string) {
// do whatever async things you need to do here
return this
}
#ready: Promise
get ready() {
return this.#ready
}
}
const my_foo = await new Foo(url).ready
2)
// bar.svelte.ts
export class Bar {
constructor(args: Required) {
if (args instanceof Bar) {
args = $state.snapshot(args)
}
Object.assign(this, args)
}
#name: string = $state()
get name() {
return this.#name
}
private set name(v) {
this.#name = v
}
#age: number = $state()
get age() {
return this.#age
}
set age(v) {
this.#age = v
}
pet: string = $state()
protected toJSON() {
return {
name: this.name,
age: this.age,
pet: this.pet,
}
}
}
// main.svelte
import { Bar } from './bar.svelte.ts'
const my_bar = new Bar({
name: "fooman",
age: 123,
pet: "ghost",
})
const my_other_bar = new Bar(my_bar)
setTimeout(()=> {
// should report error: Property 'name' is private and only accessible within class 'Bar'.
my_bar.name = "barman"
}, 1000)
setTimeout(()=> {
my_other_bar.pet = "cat"
// should report error: Type 'string' is not assignable to type 'number'.
my_other_bar.age = "old"
}, 2000)
{ my_bar.name } - { my_bar.age } - { my_bar.pet }
{ my_other_bar.name } - { my_other_bar.age } - { my_other_bar.pet }
TWIS