How to create type-safe links route parameters with TanStack/Router and MUI?
20:36 09 Sep 2023

I am trying to use tanstack-router with the MUI Link component.

When I try to use the MUI component with a route that accepts a parameter, I get a compile error about Type '{ itemId: string; }' is not assignable to type 'Omit'.

How can I structure my code so that TypeScript understands the parameters for the route?

Note that the MUI Link appears to function correctly, it just doesn't type-check.

The target route I'm trying to link to looks like:

export const itemViewRoute = new Route({
  getParentRoute: () => rootRoute,
  path: 'item/$itemId/view',
  component: ViewItem
});

export function ViewItem(){
  const params = useParams({from: itemViewRoute.id})
  return <>
    
      
        Description: "description of {params.itemId}"
      

    
  
}

I can link to the route with the TanStack Link and the type checking works fine, but the created link is not integrated with MUI (styling, functionality, etc.):


  
    View Item 42 (RouterLink)
  

When I try to use the MUI Link, like this:


  
    View Item 42 (MuiLink)
  

I get a compile error:


src/Route/Home.tsx:35:13 - error TS2769: No overload matches this call.
  Overload 1 of 2, '(props: { component: LinkComponent<{}>; } & Omit & { children?: ReactNode; ... 5 more .
..; variant?: OverridableStringUnion<...> | undefined; } & CommonProps & Omit<...>): Element | null', gave the following error.
    Type '{ itemId: string; }' is not assignable to type 'ParamsReducer<{ itemId?: string | undefined; } & Record & Record<"itemId", string>, { itemId?: strin
g | undefined; } & Partial<{}> & Omit & Partial<...> & Partial<...>>'.
      Type '{ itemId: string; }' is not assignable to type '{ itemId?: string | undefined; } & Partial<{}> & Omit & Partial> & Partial & Record<...>>'.
        Type '{ itemId: string; }' is not assignable to type 'Omit'.
          Property 'itemId' is incompatible with index signature.
            Type 'string' is not assignable to type 'never'.
  Overload 2 of 2, '(props: DefaultComponentProps>): Element | null', gave the following error.
    Type '{ children: string; component: LinkComponent<{}>; to: "/item/$itemId/view"; preload: string; search: {}; params: { itemId: string; }; }' is not assignable to type 
'IntrinsicAttributes & Omit & { children?: ReactNode; ... 5 more ...; variant?: OverridableStringUnion<...>
 | undefined; } & CommonProps & Omit<...>'.
      Property 'component' does not exist on type 'IntrinsicAttributes & Omit & { children?: ReactNode; ...
 5 more ...; variant?: OverridableStringUnion<...> | undefined; } & CommonProps & Omit<...>'.

 35             
    ~~~~~~~~~~~~~

  node_modules/@tanstack/router-core/build/types/link.d.ts:61:5
    61     params: ParamsReducer;
           ~~~~~~
    The expected type comes from property 'params' which is declared here on type 'IntrinsicAttributes & { component: LinkComponent<{}>; } & Omit & { ...; } & CommonProps & Omit<...>'


Found 1 error in src/Route/Home.tsx:35


Process finished with exit code 2

Following the MUI section on routing, I've customised the theme to integrate MUI with router:

export const LinkBehavior = React.forwardRef<
  HTMLAnchorElement,
  Omit & { href: RouterLinkProps['to'] }
>((props, ref) => {
  const { href, ...other } = props;
  // Map href (Material UI) -> to (react-router)
  return ;
});

const muiLightTheme = createTheme({

  components: {

    MuiLink: {
      defaultProps: {
        component: LinkBehavior,
      } as RouterLinkProps,
    },
    MuiButtonBase: {
      // should be something like `as RouteButtonProps`?
      defaultProps: {
        LinkComponent: LinkBehavior,
      },
    },
...

The repo for the project, including setup of the router: https://github.com/shorn/tater/blob/d8d6cc82d7079b820e8fc2d8be6015626683162a/src/App.tsx#L42

Versions:

"@mui/material": "5.14.7",
"@tanstack/react-router" : "0.0.1-beta.185"
reactjs typescript material-ui tanstack tanstack-router