如何结合TanStack/Router与MUI创建类型安全的路由参数链接
TanStack Router 与 MUI Link 集成的 TypeScript 类型问题
问题场景
在使用MUI Link组件跳转带参数的TanStack Router路由时,出现编译错误:
Type '{ itemId: string; }' is not assignable to type 'Omit<never, never>'
组件功能正常,但无法通过TypeScript类型检查。
相关代码示例
目标路由定义
export const itemViewRoute = new Route({ getParentRoute: () => rootRoute, path: 'item/$itemId/view', component: ViewItem }); export function ViewItem(){ const params = useParams({from: itemViewRoute.id}) return <> <SmallContentMain> <ContainerCard title={`View Item ${params.itemId}`}> <TextSpan>Description: "description of {params.itemId}"</TextSpan> </ContainerCard> </SmallContentMain> </> }
正常工作的TanStack RouterLink
<ListItem> <RouterLink to={itemViewRoute.to} params={{itemId: "42"}} search={{}} > View Item 42 (RouterLink) </RouterLink> </ListItem>
报错的MUI Link用法
<ListItem> <MuiLink component={RouterLink} to={itemViewRoute.to} preload={'intent'} search={{}} params={{itemId: '42'}} > View Item 42 (MuiLink) </MuiLink> </ListItem>
完整错误信息
src/Route/Home.tsx:35:13 - error TS2769: No overload matches this call. Overload 1 of 2, '(props: { component: LinkComponent<{}>; } & Omit<TypographyOwnProps, "children" | "classes" | "color" | "variant"> & { 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<never, string> & Record<"itemId", string>, { itemId?: string | undefined; } & Partial<{}> & Omit<never, never> & Partial<...> & Partial<...>>'. Type '{ itemId: string; }' is not assignable to type '{ itemId?: string | undefined; } & Partial<{}> & Omit<never, never> & Partial<Record<never, string>> & Partial<Record<never, string> & Record<...>>'. Type '{ itemId: string; }' is not assignable to type 'Omit<never, never>'. Property 'itemId' is incompatible with index signature. Type 'string' is not assignable to type 'never'. Overload 2 of 2, '(props: DefaultComponentProps<LinkTypeMap<{}, "a">>): 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<TypographyOwnProps, "children" | "classes" | "color" | "variant"> & { children?: ReactNode; ... 5 more ...; variant?: OverridableStringUnion<...> | undefined; } & CommonProps & Omit<...>'. Property 'component' does not exist on type 'IntrinsicAttributes & Omit<TypographyOwnProps, "children" | "classes" | "color" | "variant"> & { children?: ReactNode; ... 5 more ...; variant?: OverridableStringUnion<...> | undefined; } & CommonProps & Omit<...>'. 35 <MuiLink component={RouterLink} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 to={itemViewRoute.to} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... 38 search={{}} params={{itemId: '42'}} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 > ~~~~~~~~~~~~~ node_modules/@tanstack/router-core/build/types/link.d.ts:61:5 61 params: ParamsReducer<TFromFullParams, TToFullParams>; ~~~~~~ The expected type comes from property 'params' which is declared here on type 'IntrinsicAttributes & { component: LinkComponent<{}>; } & Omit<TypographyOwnProps, "children" | "classes" | "color" | "variant"> & { ...; } & CommonProps & Omit<...>' Found 1 error in src/Route/Home.tsx:35 Process finished with exit code 2
当前已配置的主题集成代码
export const LinkBehavior = React.forwardRef< HTMLAnchorElement, Omit<RouterLinkProps, 'to'> & { href: RouterLinkProps['to'] } >((props, ref) => { const { href, ...other } = props; // Map href (Material UI) -> to (react-router) return <RouterLink ref={ref} to={href} {...other} />; }); const muiLightTheme = createTheme({ components: { MuiLink: { defaultProps: { component: LinkBehavior, } as RouterLinkProps, }, MuiButtonBase: { // should be something like `as RouteButtonProps`? defaultProps: { LinkComponent: LinkBehavior, }, }, ...
版本信息
"@mui/material": "5.14.7", "@tanstack/react-router" : "0.0.1-beta.185"
解决方案
1. 自定义带类型的MUI Link组件
创建封装组件,显式合并MUI Link与TanStack RouterLink的属性类型,让TypeScript正确识别路由参数:
import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material'; import { RouterLink, RouterLinkProps } from '@tanstack/react-router'; // 合并两种组件的属性类型,排除冲突字段 type MuiTanStackLinkProps<TTo> = Omit<MuiLinkProps, 'component' | 'href'> & Omit<RouterLinkProps<TTo>, 'to'> & { to: RouterLinkProps<TTo>['to']; }; export const MuiTanStackLink = <TTo,>(props: MuiTanStackLinkProps<TTo>) => { const { to, ...muiProps } = props; return ( <MuiLink component={RouterLink} to={to} {...muiProps} /> ); };
2. 使用自定义组件跳转路由
替换原MuiLink用法,改用自定义的MuiTanStackLink:
<ListItem> <MuiTanStackLink to={itemViewRoute.to} preload={'intent'} search={{}} params={{ itemId: '42' }} > View Item 42 (MuiTanStackLink) </MuiTanStackLink> </ListItem>
3. 全局主题配置(可选)
若希望全局默认使用该集成组件,修改主题配置:
const muiLightTheme = createTheme({ components: { MuiLink: { defaultComponent: MuiTanStackLink, }, // 其他组件配置... }, });
原理说明
错误根源是MUI Link的默认类型未包含TanStack RouterLink的params等属性类型,导致TypeScript无法识别路由参数。通过自定义组件合并两种组件的类型定义,让TypeScript能够正确推断参数类型,从而通过类型检查。
内容的提问来源于stack exchange,提问作者Shorn
相关产品推荐
相关产品推荐

