1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ぼっちアドベントカレンダー by bon10Advent Calendar 2024

Day 11

react-scrollが型エラーになってビルドが通らないので調査した

Last updated at Posted at 2024-12-12

最初に結論

対応としては以下のどれかになる。プロダクト・プロジェクトの状況に応じて選択しましょう。

  • Reactを 19 にアップグレードする
  • 独自の型定義ファイル(global.d.tsとかindex.d.tsとか)を作って回避
  • package-lock.json、yarn.lockを元に戻す
  • バージョン管理をpnpmに変える
  • yarn patchを使って@types/react-scrollの依存関係にある@types/reactのバージョンを'*' → '^18' とかに変更する

何が起きたか

起きた型エラーの内容は以下です。

'Link' cannot be used as a JSX component.
  Its type 'typeof Link' is not a valid JSX element type.
    Types of construct signatures are incompatible.
      Type 'new (props: LinkProps) => Link' is not assignable to type 'new (props: any, deprecatedLegacyContext?: any) => Component<any, any, any>'.
        Property 'refs' is missing in type 'Component<LinkProps, {}, any>' but required in type 'Component<any, any, any>'.ts(2786)
index.d.ts(1033, 9): 'refs' is declared here.

実装は以下のようにコンポーネント化していました。

import { Link } from 'react-scroll';

export const ScrollLink: React.FC<Props> = ({
  className,
  children,
  duration = 500,
  offset = -100,
  onClick,
  to,
  activeClass = 'active',
}) => {
  return (
    <Link
      activeClass={activeClass}
      duration={duration}
      smooth={true}
      spy={true}
      {...{ className, offset, onClick, to }}
    >
      {children}
    </Link>
  );
};

type Props = {
  activeClass?: string;
  children: React.ReactNode;
  className?: string;
  duration?: number;
  offset?: number;
  onClick?: () => void;
  to: string;
};

原因

調べた限りでは React19 にてReact.Componentから、refs が削除されたからというのが根本原因でした。

@types/react:18.3.16 では以下のように書かれてますが、これが @types/react:19.0.1 では消えてます。

index.d.ts
/**
         * @deprecated
         *
         * @see {@link https://legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs Legacy React Docs}
         */
        refs: {
            [key: string]: ReactInstance;
        };

該当のGithubも載せておきます。

@types/react v18:


私は yarn を使ってパッケージ管理をしてます。 yarn.lockをみると @types/react-scroll の依存関係で @types/react* で指定されており、その結果 @types/react の最新バージョンを依存関係として親切にもインストールしてくれるようです。

yarn.lock(抜粋)
"@types/react-scroll@^1.8.10":
  version "1.8.10"
  resolved "https://registry.yarnpkg.com/@types/react-scroll/-/react-scroll-1.8.10.tgz#585a5c4bd0654434f3e55a08e94ed2e048bae7c7"
  integrity sha512-RD4Z7grbdNGOKwKnUBKar6zNxqaW3n8m9QSrfvljW+gmkj1GArb8AFBomVr6xMOgHPD3v1uV3BrIf01py57daQ==
  dependencies:
    "@types/react" "*"

package.jsonで以下のように依存関係を指定したんですが、解決せず。。

package.json(抜粋)
{
  "resolutions": {
    "@types/react": "^18.3.16"
  }
}

または

package.json(抜粋)
"resolutions": {
    "@types/react": "^18.3.12",
    "@types/react-scroll/@types/react": "^18.3.12",
    "@types/hoist-non-react-statics/@types/react": "^18.3.12",
    "@repo/next-js/@types/react-dom/@types/react": "^18.3.12"
  }

どうもパッケージの内部の依存関係についてはnpmもyarnも開発者側から指定するのは難しいみたいです。 
ただ、 yarn patch を使えばもしかしたらうまくいくかもしれません(未確認)
以下のように node_modules 配下を直接編集。

node_modules/@types/react-scroll/package.json
"scripts": {},
    "dependencies": {
        "@types/react": "^18"
    },

その後 yarn patch を実行するます。

yarn patch @types/react-scroll

なお、pnpmだとこの辺の依存関係をもっと楽に解消してくれるようです。

回避策(一時的)

冒頭に述べたようにReactを19に上げてしまえば基本問題ないのですが、プロダクトの仕様上簡単にはできんねん。。。という場合もあるでしょう。そのときの解決策は個別に型定義ファイルを作ってOverrideしてあげる感じになると思います。

ディレクトリ直下(monorepoの場合は各Appのディレクトリ配下)に global.d.ts みたいなファイルを作成し、以下を記述。

global.d.ts
declare module 'react-scroll' {
  interface ReactScrollLinkProps {
    absolute?: boolean | undefined;
    activeClass?: string | undefined;
    activeStyle?: React.CSSProperties | undefined;
    containerId?: string | undefined;
    delay?: number | undefined;
    duration?: number | string | ((distance: number) => number) | undefined;
    hashSpy?: boolean | undefined;
    horizontal?: boolean | undefined;
    ignoreCancelEvents?: boolean | undefined;
    isDynamic?: boolean | undefined;
    offset?: number | undefined;
    onClick?(): void;
    onSetActive?(to: string, element: HTMLElement): void;
    onSetInactive?(to: string, element: HTMLElement): void;
    saveHashHistory?: boolean | undefined;
    smooth?: boolean | string | undefined;
    spy?: boolean | undefined;
    spyThrottle?: number | undefined;
    to: string;
  }

  type LinkProps = ReactScrollLinkProps & React.HTMLProps<HTMLButtonElement>;

  class Link extends React.Component<LinkProps> {}

  export { Link };
}

package.jsonでは以下のように@types/react@types/react-scroll をバージョンを指定してインストール。

package.json(抜粋)
"devDependencies": {
  "@types/react": "^18.3.12",
  "@types/react-scroll": "^1.8.10",
}

これで実装側では型定義を @types/react": "^18.3.12" のパッケージに対して参照してくれます。ただし、永遠にこの対策をしているとreact-scrollのバージョンアップに追随できないので注意しましょう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?