最初に結論
対応としては以下のどれかになる。プロダクト・プロジェクトの状況に応じて選択しましょう。
- 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
では消えてます。
/**
* @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
の最新バージョンを依存関係として親切にもインストールしてくれるようです。
"@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で以下のように依存関係を指定したんですが、解決せず。。
{
"resolutions": {
"@types/react": "^18.3.16"
}
}
または
"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 配下を直接編集。
"scripts": {},
"dependencies": {
"@types/react": "^18"
},
その後 yarn patch
を実行するます。
yarn patch @types/react-scroll
なお、pnpmだとこの辺の依存関係をもっと楽に解消してくれるようです。
回避策(一時的)
冒頭に述べたようにReactを19に上げてしまえば基本問題ないのですが、プロダクトの仕様上簡単にはできんねん。。。という場合もあるでしょう。そのときの解決策は個別に型定義ファイルを作ってOverrideしてあげる感じになると思います。
ディレクトリ直下(monorepoの場合は各Appのディレクトリ配下)に 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
をバージョンを指定してインストール。
"devDependencies": {
"@types/react": "^18.3.12",
"@types/react-scroll": "^1.8.10",
}
これで実装側では型定義を @types/react": "^18.3.12"
のパッケージに対して参照してくれます。ただし、永遠にこの対策をしているとreact-scrollのバージョンアップに追随できないので注意しましょう。