ractivejs/ractive

Typescript error when using class based component in components registry

Closed this issue · 6 comments

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>;

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?

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

It seems that it's related to this commit

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

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

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.

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.

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!