ractivejs / ractive

Next-generation DOM manipulation
http://ractive.js.org
MIT License
5.94k stars 396 forks source link

Typescript error when using class based component in components registry #3360

Closed marcalexiei closed 3 years ago

marcalexiei commented 3 years ago

Description:

Ractive class based components get a type error when included inside components registry.

Versions affected:

All

Platforms affected:

All

Reproduction:

class MyComponent extends Ractive {
  constructor(opts?: InitOpts) { super(opts); }
}

Ractive.extendWith(MyComponent, { template: 'hello!' });

class MyMainComponent extends Ractive {
  constructor(opts?: InitOpts) { super(opts); }
}

Ractive.extendWith(MyMainComponent, {
  components: {
    MyComponent, // <---- Error 1
  },
});

const AnotherMainComponent = Ractive.extend({
  components: { // <---- Error 2
    MyComponent, 
  },
});

Error 1: TS2322: Type 'typeof MyComponent' is not assignable to type 'Component'.   Property 'css' is missing in type 'typeof MyComponent' but required in type 'Static<Ractive<Ractive>>'.

Error 2: Type '{ MyComponent: typeof MyComponent; }' is not assignable to type 'Registry & { MyComponent: typeof MyComponent; }'.   Type '{ MyComponent: typeof MyComponent; }' is not assignable to type 'Registry'

Workaround

Add as unknown as Component casting.

Proposed fix

Update definition of component with typeof Ractive | Promise<typeof Ractive>

export type Component = Static | Promise<Static> | typeof Ractive | Promise<typeof Ractive>;
evs-chris commented 3 years ago

Is this on dev or 1.3? I remember running into something like this, but I though it was fixed by flagging the css property as optional. If you provide an empty string for css does it compiler without complaint?

marcalexiei commented 3 years ago

1.3.

Now I tried with edge but I get a different error:

1 - 'U' could be instantiated with an arbitrary type which could be unrelated to 'Ractive> & U'. ``` Type 'typeof MyComponent' is not assignable to type 'Component'. Type 'typeof MyComponent' is not assignable to type 'Static>>'. The types of 'extend(...).defaults' are incompatible between these types. Type 'import("*/node_modules/ractive/typings/ractive").Registries> & U>' is not assignable to type 'import("*/node_modules/ractive/typings/ractive").Registries> & U>'. Two different types with this name exist, but they are unrelated. Type 'import("*/node_modules/ractive/typings/ractive").Ractive> & U' is not assignable to type 'import("*/node_modules/ractive/typings/ractive").Ractive> & U'. Two different types with this name exist, but they are unrelated. Type 'Ractive> & U' is not assignable to type 'U'. 'U' could be instantiated with an arbitrary type which could be unrelated to 'Ractive> & U'. ```
2 - Type 'typeof MyComponent' is not assignable to type 'Static>>'. ``` Type '{ MyComponent: typeof MyComponent; }' is not assignable to type 'Registry & { MyComponent: typeof MyComponent; }'. Type '{ MyComponent: typeof MyComponent; }' is not assignable to type 'Registry'. Property 'MyComponent' is incompatible with index signature. Type 'typeof MyComponent' is not assignable to type 'Component'. Type 'typeof MyComponent' is not assignable to type 'Static>>'. ```

It seems that it's related to this commit

I reverted that commit and the issue is no longer present.

marcalexiei commented 3 years ago

I have created a repository where the issue can be reproduced: https://github.com/marcalexiei/ractive-sandbox

marcalexiei commented 3 years ago

I find another solution to the problem:

Restore previous return type of extend functions and leaving opts as an array of ExtendOpts should resolve the issue.

// For Ractive
static extend<U>(...opts: ExtendOpts<Ractive & U>[]): Static<Ractive<Ractive & U>>;

// For Static
extend<U, V extends ExtendOpts<T> = ExtendOpts<T>>(...opts: V[]): Static<Ractive<T & U>>;

IMHO this should work. Maybe there can be problems with custom methods but if someone needs them he can use extendWith as you explained here.

evs-chris commented 3 years ago

This should be resolved on edge now, once travis finishes doing its thing. I think you'll need a recent-ish version of ts, as it's doing some interesting type gymnastics to get const Foo = Ractive.extend({ foo() { return "foo"; } }, { bar() { return "bar"; } }); to type with const foo = new Foo(); foo.foo(); foo.bar();. I'd guess whatever version includes type computations and Omit. Let me know if I managed to blow anything up.

marcalexiei commented 3 years ago

I think you'll need a recent-ish version of ts

No problem. we are using 4.2.2

Let me know if I managed to blow anything up.

No issue encountered so far.

Thanks!