gatsby: [TS] Link is incompatible with React.forwardRef due to ref type mismatch

Preliminary Checks

Description

In a TypeScript environment, Gatsby’ Link component is not compatible with React.forwardRef due to a ref type mismatch.

Reproduction Link

https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBDAnmApnA3nA4gQxgZwCNEAZYAOwGsAFKCMfOAXzgDM6Q4AiAczyMRcA3AChQkWBjhkqzNh258CxYWPDR4AJRQ4AxjAA0U1tADuOKABNtrOewicuUHftUiUADwnwkqOAFlSCho6BjgAXmx+YhkQ+nwAHgBXKnIIU3IAPlF3Lw04XQhyfHhA2Ii2MwtrFFYEgAkAFX8SAEFyXQALaABRABsUEBRyQwCgqlp4zIAKETg2FP1gIrHY6bBQ-CNnVgBKDDn5uGcYJKhyOATy9AA6O434lh3w9B2WPRhgADcUAGE+nD4fAAORwQ3CXA+3xQXDgAHpsocmCJdkIgA

Steps to Reproduce

Run this code:

import type { GatsbyLinkProps } from "gatsby";
import { Link } from "gatsby";
import React, { forwardRef } from "react";

export type MyLinkProps = GatsbyLinkProps<unknown>;

export const MyLink = forwardRef<HTMLAnchorElement, MyLinkProps>(
  function MyLink(props, ref) {
    return <Link {...props} ref={ref} activeClassName="active" />;
  }
);

Expected Result

Works normally.

Actual Result

TypeScript complains about a type mismatch on ref={ref}:

No overload matches this call.
  Overload 1 of 2, '(props: GatsbyLinkProps<unknown> | Readonly<GatsbyLinkProps<unknown>>): GatsbyLink<unknown>', gave the following error.
    Type 'ForwardedRef<HTMLAnchorElement>' is not assignable to type '((string | ((instance: GatsbyLink<unknown> | null) => void) | RefObject<GatsbyLink<unknown>>) & (string | ((instance: HTMLAnchorElement | null) => void) | RefObject<...>)) | null | undefined'.
      Type '(instance: HTMLAnchorElement | null) => void' is not assignable to type '((string | ((instance: GatsbyLink<unknown> | null) => void) | RefObject<GatsbyLink<unknown>>) & (string | ((instance: HTMLAnchorElement | null) => void) | RefObject<...>)) | null | undefined'.
        Type '(instance: HTMLAnchorElement | null) => void' is not assignable to type 'string & ((instance: HTMLAnchorElement | null) => void)'.
          Type '(instance: HTMLAnchorElement | null) => void' is not assignable to type 'string'.
  Overload 2 of 2, '(props: GatsbyLinkProps<unknown>, context: any): GatsbyLink<unknown>', gave the following error.
    Type 'ForwardedRef<HTMLAnchorElement>' is not assignable to type '((string | ((instance: GatsbyLink<unknown> | null) => void) | RefObject<GatsbyLink<unknown>>) & (string | ((instance: HTMLAnchorElement | null) => void) | RefObject<...>)) | null | undefined'.

My workaround to date depends on stripping ref from GatsbyLinkProps, and then passing my forwarded ref to deprecated prop innerRef, like so:

import type { GatsbyLinkProps } from "gatsby";
import { Link } from "gatsby";
import React, { forwardRef } from "react";

export type MyLinkProps = Omit<GatsbyLinkProps<unknown>, "ref">;

export const MyLink = forwardRef<HTMLAnchorElement, MyLinkProps>(
  function MyLink(props, ref) {
    return <Link {...props} innerRef={ref} activeClassName="active" />;
  }
);

But this wasn’t much fun to figure out, nor should it be necessary. Gatsby’s Link should be directly compatible with forwardRef out of the box.

Among other things, this would make it possible to pass component={Link} when using MUI. MUI is a (the?) leading React front end framework, and improving compatibility here would be a big plus.

Environment

Gatsby 4.4.0.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 9
  • Comments: 23 (7 by maintainers)

Most upvoted comments

Not stale.

Still not stale!

Hopefully this can be addressed as part of PR #22027, though there hasn’t been much progress there.