Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next.js: Compat with React 19 types #1

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@
"@babel/parser": "7.22.5",
"@babel/types": "7.22.5",
"@babel/traverse": "7.22.5",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15"
"@types/react": "npm:[email protected]",
"@types/react-dom": "npm:[email protected]"
},
"engines": {
"node": ">=18.17.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function AppRouterAnnouncer({ tree }: { tree: FlightRouterState }) {
}, [])

const [routeAnnouncement, setRouteAnnouncement] = useState('')
const previousTitle = useRef<string | undefined>()
const previousTitle = useRef<string | undefined>(undefined)

useEffect(() => {
let currentTitle = ''
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/client/components/error-boundary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import React from 'react'
import React, { type JSX } from 'react'
import { usePathname } from './navigation'
import { isNextRouterError } from './is-next-router-error'

Expand Down
21 changes: 13 additions & 8 deletions packages/next/src/client/components/layout-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React, {
startTransition,
Suspense,
useDeferredValue,
type JSX,
} from 'react'
import ReactDOM from 'react-dom'
import {
Expand Down Expand Up @@ -90,7 +91,9 @@ function walkAddRefetch(
* Wraps ReactDOM.findDOMNode with additional logic to hide React Strict Mode warning
*/
function findDOMNode(
// @ts-expect-error FIXME: `findDOMNode` was removed in React 19.
instance: Parameters<typeof ReactDOM.findDOMNode>[0]
// @ts-expect-error FIXME: `findDOMNode` was removed in React 19.
): ReturnType<typeof ReactDOM.findDOMNode> {
// Tree-shake for server bundle
if (typeof window === 'undefined') return null
Expand All @@ -104,11 +107,13 @@ function findDOMNode(
originalConsoleError(...messages)
}
}
// @ts-expect-error FIXME: `findDOMNode` was removed in React 19.
return ReactDOM.findDOMNode(instance)
} finally {
console.error = originalConsoleError!
}
}
// @ts-expect-error FIXME: `findDOMNode` was removed in React 19.
return ReactDOM.findDOMNode(instance)
}

Expand Down Expand Up @@ -563,14 +568,14 @@ export default function OuterLayoutRouter({

return (
/*
- Error boundary
- Only renders error boundary if error component is provided.
- Rendered for each segment to ensure they have their own error state.
- Loading boundary
- Only renders suspense boundary if loading components is provided.
- Rendered for each segment to ensure they have their own loading state.
- Passed to the router during rendering to ensure it can be immediately rendered when suspending on a Flight fetch.
*/
- Error boundary
- Only renders error boundary if error component is provided.
- Rendered for each segment to ensure they have their own error state.
- Loading boundary
- Only renders suspense boundary if loading components is provided.
- Rendered for each segment to ensure they have their own loading state.
- Passed to the router during rendering to ensure it can be immediately rendered when suspending on a Flight fetch.
*/
<TemplateContext.Provider
key={createRouterCacheKey(preservedSegment, true)}
value={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getSocketUrl } from './get-socket-url'
import type { TurbopackMsgToBrowser } from '../../../../../server/dev/hot-reloader-types'

export function useWebsocket(assetPrefix: string) {
const webSocketRef = useRef<WebSocket>()
const webSocketRef = useRef<WebSocket>(undefined)

useEffect(() => {
if (webSocketRef.current) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const INITIAL_OVERLAY_STATE: OverlayState = {
}

export function useErrorOverlayReducer() {
return useReducer<React.Reducer<OverlayState, BusEvent>>((_state, action) => {
return useReducer((_state: OverlayState, action: BusEvent): OverlayState => {
switch (action.type) {
case ACTION_BUILD_OK: {
return { ..._state, buildError: null }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import React, { useContext } from 'react'
import React, { useContext, type JSX } from 'react'
import { TemplateContext } from '../../shared/lib/app-router-context.shared-runtime'

export default function RenderFromTemplateContext(): JSX.Element {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,10 @@ function createPendingCacheNode(

// Create a deferred promise. This will be fulfilled once the dynamic
// response is received from the server.
rsc: createDeferredRsc(),
head: isLeafSegment ? createDeferredRsc() : null,
// TODO: Double check why we need to type-cast here.
// It's likely some conflict between the bounded `ReactNode = AwaitedReactNode | Promise<AwaitedReactNode>` and the unbounded `Promise<ReactNode>`
rsc: createDeferredRsc() as React.ReactNode,
head: isLeafSegment ? (createDeferredRsc() as React.ReactNode) : null,
lazyDataResolved: false,
}
}
Expand Down Expand Up @@ -789,7 +791,7 @@ type FulfilledDeferredRsc = Promise<React.ReactNode> & {
tag: Symbol
}

type RejectedDeferredRsc = Promise<React.ReactNode> & {
type RejectedDeferredRsc = Promise<Awaited<React.ReactNode>> & {
status: 'rejected'
reason: any
resolve: (value: React.ReactNode) => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ function useReducerWithReduxDevtoolsImpl(
throw new Error('Invariant: Missing ActionQueueContext')
}

const devtoolsConnectionRef = useRef<ReduxDevToolsInstance>()
const enabledRef = useRef<boolean>()
const devtoolsConnectionRef = useRef<ReduxDevToolsInstance>(undefined)
const enabledRef = useRef<boolean>(undefined)

useEffect(() => {
if (devtoolsConnectionRef.current || enabledRef.current === false) {
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/client/head-manager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { JSX } from 'react'
export const DOMAttributeNames: Record<string, string> = {
acceptCharset: 'accept-charset',
className: 'class',
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
PrivateRouteInfo,
} from '../shared/lib/router/router'

import React from 'react'
import React, { type JSX } from 'react'
import ReactDOM from 'react-dom/client'
import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime'
import mitt from '../shared/lib/mitt'
Expand Down
3 changes: 2 additions & 1 deletion packages/next/src/client/legacy/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, {
useContext,
useMemo,
useState,
type JSX,
} from 'react'
import Head from '../../shared/lib/head'
import {
Expand Down Expand Up @@ -258,7 +259,7 @@ export type ImageProps = Omit<
quality?: SafeNumber
priority?: boolean
loading?: LoadingValue
lazyRoot?: React.RefObject<HTMLElement> | null
lazyRoot?: React.RefObject<HTMLElement | null> | null
lazyBoundary?: string
placeholder?: PlaceholderValue
blurDataURL?: string
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/client/script.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import ReactDOM from 'react-dom'
import React, { useEffect, useContext, useRef } from 'react'
import React, { useEffect, useContext, useRef, type JSX } from 'react'
import type { ScriptHTMLAttributes } from 'react'
import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime'
import { DOMAttributeNames } from './head-manager'
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/client/use-intersection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type UseIntersectionObserverInit = Pick<
>

type UseIntersection = { disabled?: boolean } & UseIntersectionObserverInit & {
rootRef?: React.RefObject<HTMLElement> | null
rootRef?: React.RefObject<HTMLElement | null> | null
}
type ObserveCallback = (isVisible: boolean) => void
type Identifier = {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/client/with-router.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { type JSX } from 'react'
import type {
BaseContext,
NextComponentType,
Expand Down
13 changes: 5 additions & 8 deletions packages/next/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { type JSX } from 'react'
import type { ReactElement, ReactNode } from 'react'
import {
OPTIMIZED_FONT_PROVIDERS,
Expand Down Expand Up @@ -94,19 +94,19 @@ function getPolyfillScripts(context: HtmlProps, props: OriginProps) {
))
}

function hasComponentProps(child: any): child is React.ReactElement {
function hasComponentProps(child: any): child is React.ReactElement<any> {
return !!child && !!child.props
}

function AmpStyles({
styles,
}: {
styles?: React.ReactElement[] | React.ReactFragment
styles?: React.ReactElement[] | Iterable<React.ReactNode>
}) {
if (!styles) return null

// try to parse styles from fragment for backwards compat
const curStyles: React.ReactElement[] = Array.isArray(styles)
const curStyles: React.ReactElement<any>[] = Array.isArray(styles)
? (styles as React.ReactElement[])
: []
if (
Expand All @@ -115,7 +115,7 @@ function AmpStyles({
// @ts-ignore Property 'props' does not exist on type ReactElement
Array.isArray(styles.props.children)
) {
const hasStyles = (el: React.ReactElement) =>
const hasStyles = (el: React.ReactElement<any>) =>
el?.props?.dangerouslySetInnerHTML?.__html
// @ts-ignore Property 'props' does not exist on type ReactElement
styles.props.children.forEach((child: React.ReactElement) => {
Expand Down Expand Up @@ -837,13 +837,10 @@ export class Head extends React.Component<HeadProps> {
content={React.Children.count(head || []).toString()}
/>
)}

{children}
{optimizeFonts && <meta name="next-font-preconnect" />}

{nextFontLinkTags.preconnect}
{nextFontLinkTags.preload}

{process.env.NEXT_RUNTIME !== 'edge' && inAmpMode && (
<>
<meta
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { AppPageModule } from '../future/route-modules/app-page/module'
import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'
import type { Revalidate } from '../lib/revalidate'

import React from 'react'
import React, { type JSX } from 'react'

import RenderResult, {
type AppPageRenderResultMetadata,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { type JSX } from 'react'
import { isNotFoundError } from '../../client/components/not-found'
import {
getURLFromRedirectError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Provider for the `useServerInsertedHTML` API to register callbacks to insert
// elements into the HTML stream.

import React from 'react'
import React, { type JSX } from 'react'
import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html.shared-runtime'

export function createServerInsertedHTML() {
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/app-render/static/static-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {
} from 'react-dom/server.edge'
import type { Options as PrerenderOptions } from 'react-dom/static.edge'

import type { JSX } from 'react'

type RenderResult = {
stream: ReadableStream<Uint8Array>
postponed?: object | null
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import type { NextParsedUrlQuery } from './request-meta'
import type { Revalidate, SwrDelta } from './lib/revalidate'
import type { COMPILER_NAMES } from '../shared/lib/constants'

import React from 'react'
import React, { type JSX } from 'react'
import ReactDOMServer from 'react-dom/server.browser'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
import {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/shared/lib/app-dynamic.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { type JSX } from 'react'
import Loadable from './lazy-dynamic/loadable'

import type {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/shared/lib/dynamic.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { type JSX } from 'react'
import Loadable from './loadable.shared-runtime'

const isServerSide = typeof window === 'undefined'
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/shared/lib/get-img-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import type {
ImageLoaderPropsWithConfig,
} from './image-config'

import type { JSX } from 'react'

export interface StaticImageData {
src: string
height: number
Expand Down
6 changes: 3 additions & 3 deletions packages/next/src/shared/lib/head.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import React, { useContext } from 'react'
import React, { useContext, type JSX } from 'react'
import Effect from './side-effect'
import { AmpStateContext } from './amp-context.shared-runtime'
import { HeadManagerContext } from './head-manager-context.shared-runtime'
Expand All @@ -21,7 +21,7 @@ export function defaultHead(inAmpMode = false): JSX.Element[] {

function onlyReactElement(
list: Array<React.ReactElement<any>>,
child: React.ReactChild
child: React.ReactElement | number | string
): Array<React.ReactElement<any>> {
// React children can be "string" or "number" in this case we ignore them for backwards compat
if (typeof child === 'string' || typeof child === 'number') {
Expand All @@ -35,7 +35,7 @@ function onlyReactElement(
// @ts-expect-error @types/react does not remove fragments but this could also return ReactPortal[]
(
fragmentList: Array<React.ReactElement<any>>,
fragmentChild: React.ReactChild
fragmentChild: React.ReactElement | number | string
): Array<React.ReactElement<any>> => {
if (
typeof fragmentChild === 'string' ||
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/shared/lib/html-context.shared-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { NEXT_DATA } from './utils'
import type { FontConfig } from '../../server/font-utils'
import type { NextFontManifest } from '../../build/webpack/plugins/next-font-manifest-plugin'

import { createContext, useContext } from 'react'
import { createContext, useContext, type JSX } from 'react'

export type HtmlProps = {
__NEXT_DATA__: NEXT_DATA
Expand Down Expand Up @@ -35,7 +35,7 @@ export type HtmlProps = {
}
locale?: string
disableOptimizedLoading?: boolean
styles?: React.ReactElement[] | React.ReactFragment
styles?: React.ReactElement[] | Iterable<React.ReactNode>
head?: Array<JSX.Element | null>
crossOrigin?: 'anonymous' | 'use-credentials' | '' | undefined
optimizeCss?: any
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/shared/lib/side-effect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type React from 'react'
import { Children, useEffect, useLayoutEffect } from 'react'
import { Children, useEffect, useLayoutEffect, type JSX } from 'react'

type State = JSX.Element[] | undefined

Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/shared/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { HtmlProps } from './html-context.shared-runtime'
import type { ComponentType } from 'react'
import type { ComponentType, JSX } from 'react'
import type { DomainLocale } from '../../server/config'
import type { Env } from '@next/env'
import type { IncomingMessage, ServerResponse } from 'http'
Expand Down Expand Up @@ -191,7 +191,7 @@ export type DocumentContext = NextPageContext & {
}

export type DocumentInitialProps = RenderPageResult & {
styles?: React.ReactElement[] | React.ReactFragment | JSX.Element
styles?: React.ReactElement[] | Iterable<React.ReactNode> | JSX.Element
}

export type DocumentProps = DocumentInitialProps & HtmlProps
Expand Down
4 changes: 4 additions & 0 deletions packages/next/types/react-dom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ declare module 'react-dom/server-rendering-stub'
declare module 'react-dom/server.browser'

declare module 'react-dom/server.edge' {
import type { JSX } from 'react'

/**
* https://github.com/facebook/react/blob/aec521a96d3f1bebc2ba38553d14f4989c6e88e0/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js#L329-L333
*/
Expand Down Expand Up @@ -75,6 +77,8 @@ declare module 'react-dom/server.edge' {
}

declare module 'react-dom/static.edge' {
import type { JSX } from 'react'

/**
* https://github.com/facebook/react/blob/aec521a96d3f1bebc2ba38553d14f4989c6e88e0/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js#L329-L333
*/
Expand Down
Loading
Loading