router icon indicating copy to clipboard operation
router copied to clipboard

Using 'title' in a Child Route causes a Type Error

Open thron7 opened this issue 4 years ago • 3 comments

Vaadin 21.0.2, @vaadin/router 1.7.4 here. With a route configuration like this

 { path: 'foo',
    component: 'foo-view',
    title: 'Foo',
    children: [
       { path: 'bar',
         component: 'bar-view',
         title: 'Bar'
       }]
  }

I get the following compile error

TS2322: Type '{ path: string; component: string; icon: string; title: string; children: { 
  path: string; component: string; title: string; children: { 
    path: string; component: string; }[]; }[]; }' is not assignable to type 'ViewRoute'.

Type '{ path: string; component: string; icon: string; title: string; children: { 
  path: string; component: string; title: string; children: { 
    path: string; component: string; }[]; }[]; }' is not assignable to type 'RouteWithRedirect & { 
      title?: string | undefined; icon?: string | undefined; children?: ViewRoute[] | undefined; }'.

Property 'redirect' is missing in type '{ path: string; component: string; icon: string; title: string; children: {
  path: string; component: string; title: string; children: { 
    path: string; component: string; }[]; }[]; }' but required in type 'RouteWithRedirect'.

The error disappears when I remove the title: 'Bar' line.

  • Adding an empty 'redirect' attribute causes other problems, and I don't want to redirect, actually.
  • I don't understand why the compiler infers a type of 'RouteWithRedirect' here?! 'RouteWithComponent' would seem more appropriate, no?!
  • Still, it is not clear to me why this would be caused by adding a 'title' attribute in the child route. Can I not use a 'title' attribute on child routes? The definition of the ViewType type seems to suggest so.

thron7 avatar Oct 28 '21 10:10 thron7

Ok, so one way to work around this issue is to cast the child object to ViewRoute:

{ path: 'foo',
    component: 'foo-view',
    title: 'Foo',
    children: [
       <ViewRoute>{ path: 'bar',
         component: 'bar-view',
         title: 'Bar'
       }]
  }

But why is this necessary?

thron7 avatar Oct 28 '21 10:10 thron7

I think this is not an issue in vaadin/router but an issue in how the router is being used in the code generated from https://start.vaadin.com/ which defines:

export type ViewRoute = Route & {
  title?: string;
  icon?: string;
  children?: ViewRoute[];
};

The children?: ViewRoute[]; doesn't have the intended effect as it's not possible to override a field of a parent type/interface so simply in TypeScript. It's basically a bug in the ViewRoute definition in the application code but the TS error you get in this situation is very confusing and hard to debug.

This is why it works when you explicitly cast the type of children. I also ran into this once and then solved it by doing something like children: [ ... ] as ViewRoute[] iirc.

Just now when searching for the problem again I found this https://stackoverflow.com/questions/51591792/typescript-overwrite-a-field-from-an-extended-interface and it seems that it's possible to fix the issue without explicit casting by changing the ViewRoute definition to this (using Omit<>):

export type ViewRoute = Omit<Route, 'children'> & {
  title?: string;
  icon?: string;
  children?: ViewRoute[];
};

I just tried and using this it gets rid of the error that would otherwise happen when you add title into one of the routes under children.

Haprog avatar Nov 03 '21 12:11 Haprog

I created an issue about this in the private repository of start.vaadin.com. This public issue could probably be moved to https://github.com/vaadin/vaadin.com/issues

Haprog avatar Nov 03 '21 13:11 Haprog