Skip to content

Commit 902fb5c

Browse files
authored
TypeScript improvements to createInertiaApp() and unifying it across adapters (#2648)
* wip * wip * wip * wip * wip * Update createInertiaApp.ts * refactor * Vue refactor * Svelte refactor * Update createInertiaApp.ts * Refactor * Update createInertiaApp.ts * Update createInertiaApp.ts * wip * Renaming
1 parent 0f4ae63 commit 902fb5c

File tree

17 files changed

+308
-205
lines changed

17 files changed

+308
-205
lines changed

packages/core/src/page.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { hrefToUrl, isSameUrlWithoutHash } from './url'
77

88
class CurrentPage {
99
protected page!: Page
10-
protected swapComponent!: PageHandler
10+
protected swapComponent!: PageHandler<any>
1111
protected resolveComponent!: PageResolver
1212
protected componentId = {}
1313
protected listeners: {
@@ -18,7 +18,11 @@ class CurrentPage {
1818
protected cleared = false
1919
protected pendingDeferredProps: Pick<Page, 'deferredProps' | 'url' | 'component'> | null = null
2020

21-
public init({ initialPage, swapComponent, resolveComponent }: RouterInitParams) {
21+
public init<ComponentType = Component>({
22+
initialPage,
23+
swapComponent,
24+
resolveComponent,
25+
}: RouterInitParams<ComponentType>) {
2226
this.page = initialPage
2327
this.swapComponent = swapComponent
2428
this.resolveComponent = resolveComponent

packages/core/src/router.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ export class Router {
4848
interruptible: false,
4949
})
5050

51-
public init({ initialPage, resolveComponent, swapComponent }: RouterInitParams): void {
51+
public init<ComponentType = Component>({
52+
initialPage,
53+
resolveComponent,
54+
swapComponent,
55+
}: RouterInitParams<ComponentType>): void {
5256
currentPage.init({
5357
initialPage,
5458
resolveComponent,

packages/core/src/types.ts

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ export interface ClientSideVisitOptions<TProps = Page['props']> {
162162

163163
export type PageResolver = (name: string) => Component
164164

165-
export type PageHandler = ({
165+
export type PageHandler<ComponentType = Component> = ({
166166
component,
167167
page,
168168
preserveState,
169169
}: {
170-
component: Component
170+
component: ComponentType
171171
page: Page
172172
preserveState: boolean
173173
}) => Promise<unknown>
@@ -363,10 +363,10 @@ export type PollOptions = {
363363

364364
export type VisitHelperOptions<T extends RequestPayload = RequestPayload> = Omit<VisitOptions<T>, 'method' | 'data'>
365365

366-
export type RouterInitParams = {
366+
export type RouterInitParams<ComponentType = Component> = {
367367
initialPage: Page
368368
resolveComponent: PageResolver
369-
swapComponent: PageHandler
369+
swapComponent: PageHandler<ComponentType>
370370
}
371371

372372
export type PendingVisitOptions = {
@@ -388,7 +388,45 @@ export type InternalActiveVisit = ActiveVisit & {
388388
export type VisitId = unknown
389389
export type Component = unknown
390390

391-
export type InertiaAppResponse = Promise<{ head: string[]; body: string } | void>
391+
interface CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn> {
392+
resolve: TComponentResolver
393+
setup: (options: TSetupOptions) => TSetupReturn
394+
title?: HeadManagerTitleCallback
395+
}
396+
397+
export interface CreateInertiaAppOptionsForCSR<
398+
SharedProps extends PageProps,
399+
TComponentResolver,
400+
TSetupOptions,
401+
TSetupReturn,
402+
> extends CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn> {
403+
id?: string
404+
page?: Page<SharedProps>
405+
progress?:
406+
| false
407+
| {
408+
delay?: number
409+
color?: string
410+
includeCSS?: boolean
411+
showSpinner?: boolean
412+
}
413+
render?: undefined
414+
}
415+
416+
export interface CreateInertiaAppOptionsForSSR<
417+
SharedProps extends PageProps,
418+
TComponentResolver,
419+
TSetupOptions,
420+
TSetupReturn,
421+
> extends CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn> {
422+
id?: undefined
423+
page: Page<SharedProps>
424+
progress?: undefined
425+
render: unknown
426+
}
427+
428+
export type InertiaAppSSRResponse = { head: string[]; body: string }
429+
export type InertiaAppResponse = Promise<InertiaAppSSRResponse | void>
392430

393431
export type HeadManagerTitleCallback = (title: string) => string
394432
export type HeadManagerOnUpdateCallback = (elements: string[]) => void

packages/react/src/App.ts

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,52 @@
1-
import { createHeadManager, PageHandler, router } from '@inertiajs/core'
2-
import { createElement, useEffect, useMemo, useState } from 'react'
1+
import {
2+
createHeadManager,
3+
HeadManagerOnUpdateCallback,
4+
HeadManagerTitleCallback,
5+
Page,
6+
PageHandler,
7+
PageProps,
8+
router,
9+
} from '@inertiajs/core'
10+
import { createElement, FunctionComponent, ReactNode, useEffect, useMemo, useState } from 'react'
311
import HeadContext from './HeadContext'
412
import PageContext from './PageContext'
13+
import { LayoutFunction, ReactComponent, ReactPageHandlerArgs } from './types'
514

615
let currentIsInitialPage = true
716
let routerIsInitialized = false
8-
let swapComponent: PageHandler = async () => {
17+
let swapComponent: PageHandler<ReactComponent> = async () => {
918
// Dummy function so we can init the router outside of the useEffect hook. This is
1019
// needed so `router.reload()` works right away (on mount) in any of the user's
1120
// components. We swap in the real function in the useEffect hook below.
1221
currentIsInitialPage = false
1322
}
1423

15-
export default function App({
24+
type CurrentPage = {
25+
component: ReactComponent | null
26+
page: Page
27+
key: number | null
28+
}
29+
30+
export interface InertiaAppProps<SharedProps extends PageProps = PageProps> {
31+
children?: (options: { component: ReactComponent; props: PageProps; key: number | null }) => ReactNode
32+
initialPage: Page<SharedProps>
33+
initialComponent?: ReactComponent
34+
resolveComponent?: (name: string) => ReactComponent | Promise<ReactComponent>
35+
titleCallback?: HeadManagerTitleCallback
36+
onHeadUpdate?: HeadManagerOnUpdateCallback
37+
}
38+
39+
export type InertiaApp = FunctionComponent<InertiaAppProps>
40+
41+
export default function App<SharedProps extends PageProps = PageProps>({
1642
children,
1743
initialPage,
1844
initialComponent,
1945
resolveComponent,
2046
titleCallback,
2147
onHeadUpdate,
22-
}) {
23-
const [current, setCurrent] = useState({
48+
}: InertiaAppProps<SharedProps>) {
49+
const [current, setCurrent] = useState<CurrentPage>({
2450
component: initialComponent || null,
2551
page: initialPage,
2652
key: null,
@@ -35,17 +61,17 @@ export default function App({
3561
}, [])
3662

3763
if (!routerIsInitialized) {
38-
router.init({
64+
router.init<ReactComponent>({
3965
initialPage,
40-
resolveComponent,
66+
resolveComponent: resolveComponent!,
4167
swapComponent: async (args) => swapComponent(args),
4268
})
4369

4470
routerIsInitialized = true
4571
}
4672

4773
useEffect(() => {
48-
swapComponent = async ({ component, page, preserveState }) => {
74+
swapComponent = async ({ component, page, preserveState }: ReactPageHandlerArgs) => {
4975
if (currentIsInitialPage) {
5076
// We block setting the current page on the initial page to
5177
// prevent the initial page from being re-rendered again.
@@ -73,18 +99,18 @@ export default function App({
7399

74100
const renderChildren =
75101
children ||
76-
(({ Component, props, key }) => {
77-
const child = createElement(Component, { key, ...props })
102+
(({ component, props, key }) => {
103+
const child = createElement(component, { key, ...props })
78104

79-
if (typeof Component.layout === 'function') {
80-
return Component.layout(child)
105+
if (typeof component.layout === 'function') {
106+
return (component.layout as LayoutFunction)(child)
81107
}
82108

83-
if (Array.isArray(Component.layout)) {
84-
return Component.layout
109+
if (Array.isArray(component.layout)) {
110+
return (component.layout as any)
85111
.concat(child)
86112
.reverse()
87-
.reduce((children, Layout) => createElement(Layout, { children, ...props }))
113+
.reduce((children: any, Layout: any) => createElement(Layout, { children, ...props }))
88114
}
89115

90116
return child
@@ -97,7 +123,7 @@ export default function App({
97123
PageContext.Provider,
98124
{ value: current.page },
99125
renderChildren({
100-
Component: current.component,
126+
component: current.component,
101127
key: current.key,
102128
props: current.page.props,
103129
}),

0 commit comments

Comments
 (0)