-
-
Save zackdotcomputer/d7af9901e7db87364aad7fbfadb5c99b to your computer and use it in GitHub Desktop.
| // Created by Zack Sheppard (@zackdotcomputer) on 1/19/2021 | |
| // Freely available under MIT License | |
| // Workaround for https://github.com/vercel/next.js/issues/5533 | |
| import Link, { LinkProps } from "next/link"; | |
| import { AnchorHTMLAttributes, PropsWithChildren } from "react"; | |
| type PropTypes = LinkProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href">; | |
| /// A unified component for the next/link <Link> and a standard <a> anchor. | |
| /// Will lift href and all other props from Link up to the Link. | |
| /// Will automatically make an <a> tag containing the children and pass it remaining props. | |
| const LinkTo = ({ | |
| children, | |
| href, | |
| as, | |
| replace, | |
| scroll, | |
| shallow, | |
| prefetch, | |
| locale, | |
| ...anchorProps | |
| }: PropsWithChildren<PropTypes>) => { | |
| return ( | |
| // These props are lifted up to the `Link` element. All others are passed to the `<a>` | |
| <Link {...{ href, as, replace, scroll, shallow, prefetch, locale }}> | |
| {/* eslint-disable-next-line react/jsx-props-no-spreading */} | |
| <a {...anchorProps}>{children}</a> | |
| </Link> | |
| ); | |
| }; | |
| export default LinkTo; |
Hi there,
with typescript in strict mode, the native Link component is throwing an error: Type 'string | undefined' is not assignable to type 'Url'.
I thinkered a bit and came to the following changes:
import Link, { LinkProps } from "next/link";
import { AnchorHTMLAttributes, PropsWithChildren } from "react";
type PropTypes = LinkProps & AnchorHTMLAttributes<HTMLAnchorElement>;
/// A unified component for the next/link <Link> and a standard <a> anchor.
/// Will lift href and all other props from Link up to the Link.
/// Will automatically make an <a> tag containing the children and pass it remaining props.
const LinkTo = ({
children,
href,
as,
replace,
scroll,
shallow,
prefetch,
locale,
...anchorProps
}: PropsWithChildren<PropTypes>) => {
return (
// These props are lifted up to the `Link` element. All others are passed to the `<a>`
<Link {...{ href, as, replace, scroll, shallow, prefetch, locale }}>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<a {...anchorProps}>{children}</a>
</Link>
);
};
export default LinkTo;
What do you think about this solution? After a few tests, everything seems to work fine, the href is passed correctly to the Link-Component and is rendered into the dom (in dev and build). The LinkTo-Component even typechecks for a href, which your orginal solution does not (at least for me).
@Jak-Ch-ll looks good - I am running this with a subset of strict rather than the whole shebang so I wasn't seeing the error you got. I like your solution of just pulling in the Props from Next rather than trying to clone them, the only change I'm going to make is that I think we should Omit the href key from AnchorHTMLAttributes in our Props union so that we don't wind up confusing the type there. I'll update the gist with that now.
@zackdotocomputer ah cool, learned something new. I didn't know about Omit and that's definitly a good idea!
@adriankwiat What versions of Typescript and Next are you using? And what does your tsconfig look like? That is strange but I'm guessing it is a strictness check in typescript that is complaining that TECHNICALLY as?: Url and as: Url | undefined are different (though functionally they are basically the same).
I see that my VSCode uses dev version of typescript 4.4.0. Changing back to stable 4.3.2 resolved problem. I didn't think about that before
Oof good to know that this might break with 4.4 though
Hi made a similar solution but instead of AnchorHTMLAttributes I used HTMLAttributes. Just wanted to thank you for the solution :D

Note: this is written in Typescript 4 for Next 10. ymmv if not on those versions.