Next.js中如何为next/link的Link传递正确TypeScript类型
解决Next.js Link组件与原生a标签切换时的TypeScript类型定义问题
问题场景
我刚接触TypeScript,重构代码时遇到自定义函数参数的类型定义难题:需要根据路由判断,在Next.js的NextLink组件和原生a标签之间切换,但始终无法给函数参数设置正确的类型。简化代码如下:
utility.ts
export function getLinkAndProps (route: string, nextLink: ??) { // 尝试传入next/link的LinkProps但匹配失败 const Link = (route === "/works" || route === "/books") ? nextLink : "a" const linkProps = Link === "a" ? {rel:"noopener noreferrer", target: "_blank"} : {scroll: false}; return { Link, linkProps } }
Navbar.ts中的链接组件
import NextLink from "next/link"; import { getLinkAndProps } from "@/utils/utility"; const LinkItem = ({ children, href, path }: LinkItemProps) => { const active = path === href; const { Link, linkProps } = getLinkAndProps(href, NextLink) // TypeScript报错:NextLink缺少'href'属性 return ( <Link href={href} {...linkProps}> {children} </Link> ); }
用any类型能临时解决问题,但我想找到符合TypeScript规范的类型定义方式。曾查看Next.js Link源码写出了可行但冗余的类型:
import { LinkProps } from "next/link"; type TestProps = React.ForwardRefExoticComponent<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkProps> & LinkProps & { children?: React.ReactNode; } & React.RefAttributes<HTMLAnchorElement>>;
后来想到第二个参数不会变动,直接在函数内导入NextLink应该可行,但还是想明确正确的类型定义方法。
解决方案
方案1:直接复用NextLink的类型
不需要手动拼接复杂类型,用typeof NextLink就能直接获取NextLink组件的构造函数类型,完美匹配传入的组件实例:
修改utility.ts:
import type { NextLink } from "next/link"; export function getLinkAndProps(route: string, nextLink: typeof NextLink) { const Link = (route === "/works" || route === "/books") ? nextLink : "a"; const linkProps = Link === "a" ? { rel: "noopener noreferrer", target: "_blank" } : { scroll: false }; return { Link, linkProps } as const; // 用as const让TS推导更精确的返回类型 }
as const会让TypeScript严格推导返回值的类型,确保Link和linkProps的类型一一对应,避免后续使用时出现类型不匹配的问题。
方案2:函数内直接导入NextLink(简化版)
既然NextLink参数不会变动,完全可以在getLinkAndProps内部直接导入,省去传参和类型定义的麻烦:
修改utility.ts:
import NextLink from "next/link"; export function getLinkAndProps(route: string) { const Link = (route === "/works" || route === "/books") ? NextLink : "a"; const linkProps = Link === "a" ? { rel: "noopener noreferrer", target: "_blank" } : { scroll: false }; return { Link, linkProps } as const; }
调用时无需传NextLink:
const { Link, linkProps } = getLinkAndProps(href);
方案3:手动定义返回类型(增强可读性)
如果需要更明确的类型约束,可以手动定义返回类型,让代码逻辑更清晰:
import NextLink from "next/link"; type LinkReturnType = | { Link: typeof NextLink; linkProps: { scroll: boolean } } | { Link: "a"; linkProps: { rel: string; target: string } }; export function getLinkAndProps(route: string): LinkReturnType { const Link = (route === "/works" || route === "/books") ? NextLink : "a"; const linkProps = Link === "a" ? { rel: "noopener noreferrer", target: "_blank" } : { scroll: false }; return { Link, linkProps } as LinkReturnType; }
内容的提问来源于stack exchange,提问作者ShueiYang
相关产品推荐
相关产品推荐

