Next.js LinkとMaterial-UIのMenuItemの型定義互換性問題でハマった話
想定読者
- Next.jsでの開発を始めたばかりの方
- Material-UIを使い始めた方
- Webアプリケーション開発初学者
結論から
Next.jsとMaterial-UIの型定義の互換性問題によるエラーが発生する。
UrlObjectを用いた型定義を適切に用いる・NextLinkでMenuItemをラップすることで解決可能である。
開発環境
- Next.js: 14.2.11
- Material UI: 6.1.0
- TypeScript: 5.0
問題のあるコード
最初に、以下のようにMenuItem
とNextLink
を直接組み合わせようとすると型エラーが発生する:
interface MobileMenuProps {
menuItems: Array<{
href: string;
label: string;
}>;
}
export function MobileMenu({ menuItems }: MobileMenuProps) {
return (
<>
{menuItems.map((item) => (
<MenuItem
key={item.href}
component={NextLink}
href={item.href}
onClick={handleClose}
>
{item.label}
</MenuItem>
))}
</>
);
}
発生するエラー
No overload matches this call.
Type '{ children: string; key: string; component: <RouteType>(props: LinkProps<RouteType>) => Element; href: string; onClick: () => void; }'
is not assignable to type 'IntrinsicAttributes & { href: string; } & MenuItemOwnProps & Omit<ButtonBaseOwnProps, "classes"> & CommonProps & Omit<...>'.
Property 'component' does not exist on type 'IntrinsicAttributes & { href: string; } & MenuItemOwnProps...'
解決方法
問題を解決するために以下の2つを行なった:
-
href
の型をstring
からUrlObject
に変更 - コンポーネントの構造を変更し、
NextLink
でMenuItem
をラップする
import { MenuItem } from "@mui/material";
import NextLink from "next/link";
import { UrlObject } from "url";
interface MobileMenuProps {
menuItems: {
href: UrlObject;
label: string;
}[];
}
export function MobileMenu({ menuItems }: MobileMenuProps) {
return (
<>
{menuItems.map((item) => (
<NextLink
passHref
href={item.href}
key={item.label}
style={{ textDecoration: "none", color: "inherit" }}
>
<MenuItem onClick={handleClose}>
{item.label}
</MenuItem>
</NextLink>
))}
</>
);
}
変更点について
-
型定義の変更
-
href
の型をstring
からUrlObject
に変更することで、Next.jsの型システムとより適切に連携 -
UrlObject
は Next.js のLink
コンポーネントが期待する型定義であるためNext.js側の問題を解決
-
-
コンポーネント構造の変更
-
MenuItem
をcomponent={NextLink}
として使用する代わりに、NextLink
でMenuItem
をラップ -
passHref
プロパティを追加して、適切なリンク機能を確保 - スタイリングを追加して、デフォルトのリンクスタイルを適切に上書き (optional)
-
まとめ
Next.jsとMaterial-UIの型定義の互換性問題によるエラーが発生した。
UrlObjectを用いた型定義を適切に用いる・NextLinkでMenuItemをラップすることで問題を解決した。