@tanstack/react-router 1.40.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/CatchBoundary.d.cts +2 -2
- package/dist/cjs/Match.cjs +238 -0
- package/dist/cjs/Match.cjs.map +1 -0
- package/dist/cjs/Match.d.cts +5 -0
- package/dist/cjs/Matches.cjs +8 -249
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -11
- package/dist/cjs/RouterProvider.cjs.map +1 -1
- package/dist/cjs/RouterProvider.d.cts +2 -2
- package/dist/cjs/SafeFragment.cjs +8 -0
- package/dist/cjs/SafeFragment.cjs.map +1 -0
- package/dist/cjs/SafeFragment.d.cts +1 -0
- package/dist/cjs/ScriptOnce.cjs +28 -0
- package/dist/cjs/ScriptOnce.cjs.map +1 -0
- package/dist/cjs/ScriptOnce.d.cts +5 -0
- package/dist/cjs/Transitioner.cjs +2 -1
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/awaited.cjs +14 -71
- package/dist/cjs/awaited.cjs.map +1 -1
- package/dist/cjs/awaited.d.cts +3 -6
- package/dist/cjs/defer.cjs +7 -13
- package/dist/cjs/defer.cjs.map +1 -1
- package/dist/cjs/defer.d.cts +2 -6
- package/dist/cjs/index.cjs +11 -7
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +8 -3
- package/dist/cjs/isServerSideError.cjs +22 -0
- package/dist/cjs/isServerSideError.cjs.map +1 -0
- package/dist/cjs/isServerSideError.d.cts +5 -0
- package/dist/cjs/link.cjs +1 -0
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/matchContext.cjs +23 -0
- package/dist/cjs/matchContext.cjs.map +1 -0
- package/dist/cjs/matchContext.d.cts +2 -0
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/not-found.d.cts +2 -2
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/qss.d.cts +1 -1
- package/dist/cjs/redirects.cjs.map +1 -1
- package/dist/cjs/renderRouteNotFound.cjs +22 -0
- package/dist/cjs/renderRouteNotFound.cjs.map +1 -0
- package/dist/cjs/renderRouteNotFound.d.cts +4 -0
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/router.cjs +26 -22
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +14 -9
- package/dist/cjs/useMatch.cjs +2 -2
- package/dist/cjs/useMatch.cjs.map +1 -1
- package/dist/cjs/utils.cjs +4 -3
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +3 -2
- package/dist/esm/CatchBoundary.d.ts +2 -2
- package/dist/esm/Match.d.ts +5 -0
- package/dist/esm/Match.js +221 -0
- package/dist/esm/Match.js.map +1 -0
- package/dist/esm/Matches.d.ts +2 -11
- package/dist/esm/Matches.js +5 -246
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.d.ts +2 -2
- package/dist/esm/RouterProvider.js.map +1 -1
- package/dist/esm/SafeFragment.d.ts +1 -0
- package/dist/esm/SafeFragment.js +8 -0
- package/dist/esm/SafeFragment.js.map +1 -0
- package/dist/esm/ScriptOnce.d.ts +5 -0
- package/dist/esm/ScriptOnce.js +28 -0
- package/dist/esm/ScriptOnce.js.map +1 -0
- package/dist/esm/Transitioner.js +2 -1
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/awaited.d.ts +3 -6
- package/dist/esm/awaited.js +16 -73
- package/dist/esm/awaited.js.map +1 -1
- package/dist/esm/defer.d.ts +2 -6
- package/dist/esm/defer.js +8 -14
- package/dist/esm/defer.js.map +1 -1
- package/dist/esm/index.d.ts +8 -3
- package/dist/esm/index.js +9 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/isServerSideError.d.ts +5 -0
- package/dist/esm/isServerSideError.js +22 -0
- package/dist/esm/isServerSideError.js.map +1 -0
- package/dist/esm/link.js +1 -0
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/matchContext.d.ts +2 -0
- package/dist/esm/matchContext.js +6 -0
- package/dist/esm/matchContext.js.map +1 -0
- package/dist/esm/not-found.d.ts +2 -2
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/qss.d.ts +1 -1
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/redirects.js.map +1 -1
- package/dist/esm/renderRouteNotFound.d.ts +4 -0
- package/dist/esm/renderRouteNotFound.js +22 -0
- package/dist/esm/renderRouteNotFound.js.map +1 -0
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +14 -9
- package/dist/esm/router.js +26 -22
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/useMatch.js +1 -1
- package/dist/esm/useMatch.js.map +1 -1
- package/dist/esm/utils.d.ts +3 -2
- package/dist/esm/utils.js +4 -3
- package/dist/esm/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/Match.tsx +296 -0
- package/src/Matches.tsx +4 -333
- package/src/RouterProvider.tsx +1 -1
- package/src/SafeFragment.tsx +5 -0
- package/src/ScriptOnce.tsx +27 -0
- package/src/Transitioner.tsx +1 -1
- package/src/awaited.tsx +17 -89
- package/src/defer.ts +9 -26
- package/src/index.tsx +7 -13
- package/src/isServerSideError.tsx +23 -0
- package/src/link.tsx +2 -0
- package/src/matchContext.tsx +3 -0
- package/src/not-found.tsx +1 -1
- package/src/qss.ts +5 -6
- package/src/redirects.ts +0 -1
- package/src/renderRouteNotFound.tsx +28 -0
- package/src/route.ts +1 -1
- package/src/router.ts +50 -39
- package/src/useMatch.tsx +1 -1
- package/src/utils.ts +11 -9
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function isServerSideError(error: unknown): error is {
|
|
2
|
+
__isServerError: true
|
|
3
|
+
data: Record<string, any>
|
|
4
|
+
} {
|
|
5
|
+
if (!(typeof error === 'object' && error && 'data' in error)) return false
|
|
6
|
+
if (!('__isServerError' in error && error.__isServerError)) return false
|
|
7
|
+
if (!(typeof error.data === 'object' && error.data)) return false
|
|
8
|
+
|
|
9
|
+
return error.__isServerError === true
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function defaultDeserializeError(serializedData: Record<string, any>) {
|
|
13
|
+
if ('name' in serializedData && 'message' in serializedData) {
|
|
14
|
+
const error = new Error(serializedData.message)
|
|
15
|
+
error.name = serializedData.name
|
|
16
|
+
if (process.env.NODE_ENV === 'development') {
|
|
17
|
+
error.stack = serializedData.stack
|
|
18
|
+
}
|
|
19
|
+
return error
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return serializedData.data
|
|
23
|
+
}
|
package/src/link.tsx
CHANGED
package/src/not-found.tsx
CHANGED
package/src/qss.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
1
|
// qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -13,7 +11,7 @@
|
|
|
13
11
|
* // Expected output: "token=foo&key=value"
|
|
14
12
|
* ```
|
|
15
13
|
*/
|
|
16
|
-
export function encode(obj, pfx?: string) {
|
|
14
|
+
export function encode(obj: any, pfx?: string) {
|
|
17
15
|
let k,
|
|
18
16
|
i,
|
|
19
17
|
tmp,
|
|
@@ -44,7 +42,7 @@ export function encode(obj, pfx?: string) {
|
|
|
44
42
|
* // Example input: toValue("123")
|
|
45
43
|
* // Expected output: 123
|
|
46
44
|
*/
|
|
47
|
-
function toValue(mix) {
|
|
45
|
+
function toValue(mix: any) {
|
|
48
46
|
if (!mix) return ''
|
|
49
47
|
const str = decodeURIComponent(mix)
|
|
50
48
|
if (str === 'false') return false
|
|
@@ -61,9 +59,9 @@ function toValue(mix) {
|
|
|
61
59
|
* // Example input: decode("token=foo&key=value")
|
|
62
60
|
* // Expected output: { "token": "foo", "key": "value" }
|
|
63
61
|
*/
|
|
64
|
-
export function decode(str, pfx?: string) {
|
|
62
|
+
export function decode(str: any, pfx?: string) {
|
|
65
63
|
let tmp, k
|
|
66
|
-
const out = {},
|
|
64
|
+
const out: any = {},
|
|
67
65
|
arr = (pfx ? str.substr(pfx.length) : str).split('&')
|
|
68
66
|
|
|
69
67
|
while ((tmp = arr.shift())) {
|
|
@@ -72,6 +70,7 @@ export function decode(str, pfx?: string) {
|
|
|
72
70
|
k = tmp.slice(0, equalIndex)
|
|
73
71
|
const value = tmp.slice(equalIndex + 1)
|
|
74
72
|
if (out[k] !== void 0) {
|
|
73
|
+
// @ts-expect-error
|
|
75
74
|
out[k] = [].concat(out[k], toValue(value))
|
|
76
75
|
} else {
|
|
77
76
|
out[k] = toValue(value)
|
package/src/redirects.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import warning from 'tiny-warning'
|
|
3
|
+
import { DefaultGlobalNotFound } from './not-found'
|
|
4
|
+
import { type AnyRouter } from './router'
|
|
5
|
+
import { type AnyRoute } from './route'
|
|
6
|
+
|
|
7
|
+
export function renderRouteNotFound(
|
|
8
|
+
router: AnyRouter,
|
|
9
|
+
route: AnyRoute,
|
|
10
|
+
data: any,
|
|
11
|
+
) {
|
|
12
|
+
if (!route.options.notFoundComponent) {
|
|
13
|
+
if (router.options.defaultNotFoundComponent) {
|
|
14
|
+
return <router.options.defaultNotFoundComponent data={data} />
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (process.env.NODE_ENV === 'development') {
|
|
18
|
+
warning(
|
|
19
|
+
route.options.notFoundComponent,
|
|
20
|
+
`A notFoundError was encountered on the route with ID "${route.id}", but a notFoundComponent option was not configured, nor was a router level defaultNotFoundComponent configured. Consider configuring at least one of these to avoid TanStack Router's overly generic defaultNotFoundComponent (<div>Not Found<div>)`,
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return <DefaultGlobalNotFound />
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return <route.options.notFoundComponent data={data} />
|
|
28
|
+
}
|
package/src/route.ts
CHANGED
|
@@ -706,7 +706,7 @@ export class Route<
|
|
|
706
706
|
|
|
707
707
|
const isRoot = !options?.path && !options?.id
|
|
708
708
|
|
|
709
|
-
// eslint-disable-next-line
|
|
709
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
|
710
710
|
this.parentRoute = this.options?.getParentRoute?.()
|
|
711
711
|
|
|
712
712
|
if (isRoot) {
|
package/src/router.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createBrowserHistory, createMemoryHistory } from '@tanstack/history'
|
|
2
2
|
import { Store } from '@tanstack/react-store'
|
|
3
3
|
import invariant from 'tiny-invariant'
|
|
4
|
-
import warning from 'tiny-warning'
|
|
5
4
|
import { rootRouteId } from './root'
|
|
6
5
|
import { defaultParseSearch, defaultStringifySearch } from './searchParams'
|
|
7
6
|
import {
|
|
@@ -44,6 +43,7 @@ import type {
|
|
|
44
43
|
LoaderFnContext,
|
|
45
44
|
NotFoundRouteComponent,
|
|
46
45
|
RootRoute,
|
|
46
|
+
RouteComponent,
|
|
47
47
|
RouteMask,
|
|
48
48
|
} from './route'
|
|
49
49
|
import type {
|
|
@@ -57,22 +57,18 @@ import type {
|
|
|
57
57
|
ControlledPromise,
|
|
58
58
|
NonNullableUpdater,
|
|
59
59
|
PickAsRequired,
|
|
60
|
-
Timeout,
|
|
61
60
|
Updater,
|
|
62
61
|
} from './utils'
|
|
63
|
-
import type { RouteComponent } from './route'
|
|
64
62
|
import type {
|
|
65
63
|
AnyRouteMatch,
|
|
66
64
|
MakeRouteMatch,
|
|
67
65
|
MatchRouteOptions,
|
|
68
|
-
RouteMatch,
|
|
69
66
|
} from './Matches'
|
|
70
67
|
import type { ParsedLocation } from './location'
|
|
71
68
|
import type { SearchParser, SearchSerializer } from './searchParams'
|
|
72
69
|
import type {
|
|
73
70
|
BuildLocationFn,
|
|
74
71
|
CommitLocationOptions,
|
|
75
|
-
InjectedHtmlEntry,
|
|
76
72
|
NavigateFn,
|
|
77
73
|
} from './RouterProvider'
|
|
78
74
|
|
|
@@ -82,13 +78,16 @@ import type { NotFoundError } from './not-found'
|
|
|
82
78
|
import type { NavigateOptions, ResolveRelativePath, ToOptions } from './link'
|
|
83
79
|
import type { NoInfer } from '@tanstack/react-store'
|
|
84
80
|
import type { DeferredPromiseState } from './defer'
|
|
85
|
-
import type { ErrorInfo } from 'react'
|
|
86
81
|
|
|
87
82
|
//
|
|
88
83
|
|
|
89
84
|
declare global {
|
|
90
85
|
interface Window {
|
|
91
|
-
|
|
86
|
+
__TSR__?: {
|
|
87
|
+
matches: Array<any>
|
|
88
|
+
cleanScripts: () => void
|
|
89
|
+
dehydrated?: any
|
|
90
|
+
}
|
|
92
91
|
__TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any>>
|
|
93
92
|
}
|
|
94
93
|
}
|
|
@@ -237,7 +236,7 @@ export interface RouterOptions<
|
|
|
237
236
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#defaultoncatch-property)
|
|
238
237
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#handling-errors-with-routeoptionsoncatch)
|
|
239
238
|
*/
|
|
240
|
-
defaultOnCatch?: (error: Error, errorInfo: ErrorInfo) => void
|
|
239
|
+
defaultOnCatch?: (error: Error, errorInfo: React.ErrorInfo) => void
|
|
241
240
|
defaultViewTransition?: boolean
|
|
242
241
|
/**
|
|
243
242
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/not-found-errors#the-notfoundmode-option)
|
|
@@ -508,6 +507,20 @@ export class Router<
|
|
|
508
507
|
dehydratedData?: TDehydrated
|
|
509
508
|
viewTransitionPromise?: ControlledPromise<true>
|
|
510
509
|
manifest?: Manifest
|
|
510
|
+
AfterEachMatch?: (props: {
|
|
511
|
+
match: Pick<
|
|
512
|
+
AnyRouteMatch,
|
|
513
|
+
'id' | 'status' | 'error' | 'loadPromise' | 'minPendingPromise'
|
|
514
|
+
>
|
|
515
|
+
matchIndex: number
|
|
516
|
+
}) => any
|
|
517
|
+
serializeLoaderData?: (
|
|
518
|
+
data: any,
|
|
519
|
+
ctx: {
|
|
520
|
+
router: AnyRouter
|
|
521
|
+
match: AnyRouteMatch
|
|
522
|
+
},
|
|
523
|
+
) => any
|
|
511
524
|
|
|
512
525
|
// Must build in constructor
|
|
513
526
|
__store!: Store<RouterState<TRouteTree>>
|
|
@@ -603,7 +616,7 @@ export class Router<
|
|
|
603
616
|
}
|
|
604
617
|
|
|
605
618
|
if (
|
|
606
|
-
// eslint-disable-next-line
|
|
619
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
|
607
620
|
!this.history ||
|
|
608
621
|
(this.options.history && this.options.history !== this.history)
|
|
609
622
|
) {
|
|
@@ -622,7 +635,7 @@ export class Router<
|
|
|
622
635
|
this.buildRouteTree()
|
|
623
636
|
}
|
|
624
637
|
|
|
625
|
-
// eslint-disable-next-line
|
|
638
|
+
// eslint-disable-next-line ts/no-unnecessary-condition
|
|
626
639
|
if (!this.__store) {
|
|
627
640
|
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
628
641
|
onUpdate: () => {
|
|
@@ -1042,6 +1055,7 @@ export class Router<
|
|
|
1042
1055
|
|
|
1043
1056
|
match = {
|
|
1044
1057
|
id: matchId,
|
|
1058
|
+
index,
|
|
1045
1059
|
routeId: route.id,
|
|
1046
1060
|
params: routeParams,
|
|
1047
1061
|
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
@@ -1958,7 +1972,13 @@ export class Router<
|
|
|
1958
1972
|
)
|
|
1959
1973
|
}
|
|
1960
1974
|
|
|
1961
|
-
|
|
1975
|
+
let loaderData = await loaderPromise
|
|
1976
|
+
if (this.serializeLoaderData) {
|
|
1977
|
+
loaderData = this.serializeLoaderData(loaderData, {
|
|
1978
|
+
router: this,
|
|
1979
|
+
match,
|
|
1980
|
+
})
|
|
1981
|
+
}
|
|
1962
1982
|
checkLatest()
|
|
1963
1983
|
|
|
1964
1984
|
handleRedirectAndNotFound(match, loaderData)
|
|
@@ -2288,38 +2308,29 @@ export class Router<
|
|
|
2288
2308
|
return match
|
|
2289
2309
|
}
|
|
2290
2310
|
|
|
2291
|
-
// We use a token -> weak map to keep track of deferred promises
|
|
2292
|
-
// that are registered on the server and need to be resolved
|
|
2293
|
-
registeredDeferredsIds = new Map<string, {}>()
|
|
2294
|
-
registeredDeferreds = new WeakMap<{}, DeferredPromiseState<any>>()
|
|
2295
|
-
|
|
2296
|
-
getDeferred = (uid: string) => {
|
|
2297
|
-
const token = this.registeredDeferredsIds.get(uid)
|
|
2298
|
-
|
|
2299
|
-
if (!token) {
|
|
2300
|
-
return undefined
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
return this.registeredDeferreds.get(token)
|
|
2304
|
-
}
|
|
2305
|
-
|
|
2306
2311
|
dehydrate = (): DehydratedRouter => {
|
|
2307
2312
|
const pickError =
|
|
2308
2313
|
this.options.errorSerializer?.serialize ?? defaultSerializeError
|
|
2309
2314
|
|
|
2310
2315
|
return {
|
|
2311
2316
|
state: {
|
|
2312
|
-
dehydratedMatches: this.state.matches.map((d) =>
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2317
|
+
dehydratedMatches: this.state.matches.map((d) => {
|
|
2318
|
+
return {
|
|
2319
|
+
...pick(d, ['id', 'status', 'updatedAt']),
|
|
2320
|
+
// If an error occurs server-side during SSRing,
|
|
2321
|
+
// send a small subset of the error to the client
|
|
2322
|
+
error: d.error
|
|
2323
|
+
? {
|
|
2324
|
+
data: pickError(d.error),
|
|
2325
|
+
__isServerError: true,
|
|
2326
|
+
}
|
|
2327
|
+
: undefined,
|
|
2328
|
+
// NOTE: We don't send the loader data here, because
|
|
2329
|
+
// there is a potential that it needs to be streamed.
|
|
2330
|
+
// Instead, we render it next to the route match in the HTML
|
|
2331
|
+
// which gives us the potential to stream it via suspense.
|
|
2332
|
+
}
|
|
2333
|
+
}),
|
|
2323
2334
|
},
|
|
2324
2335
|
manifest: this.manifest,
|
|
2325
2336
|
}
|
|
@@ -2329,12 +2340,12 @@ export class Router<
|
|
|
2329
2340
|
let _ctx = __do_not_use_server_ctx
|
|
2330
2341
|
// Client hydrates from window
|
|
2331
2342
|
if (typeof document !== 'undefined') {
|
|
2332
|
-
_ctx = window.
|
|
2343
|
+
_ctx = window.__TSR__?.dehydrated
|
|
2333
2344
|
}
|
|
2334
2345
|
|
|
2335
2346
|
invariant(
|
|
2336
2347
|
_ctx,
|
|
2337
|
-
'Expected to find a
|
|
2348
|
+
'Expected to find a dehydrated data on window.__TSR__.dehydrated... but we did not. Please file an issue!',
|
|
2338
2349
|
)
|
|
2339
2350
|
|
|
2340
2351
|
const ctx = this.options.transformer.parse(_ctx) as HydrationCtx
|
package/src/useMatch.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import invariant from 'tiny-invariant'
|
|
|
3
3
|
import { useRouterState } from './useRouterState'
|
|
4
4
|
import { type RegisteredRouter } from './router'
|
|
5
5
|
import { type AnyRoute } from './route'
|
|
6
|
-
import { matchContext } from './
|
|
6
|
+
import { matchContext } from './matchContext'
|
|
7
7
|
import type { MakeRouteMatch } from './Matches'
|
|
8
8
|
import type { RouteIds } from './routeInfo'
|
|
9
9
|
import type { StrictOrFrom } from './utils'
|
package/src/utils.ts
CHANGED
|
@@ -40,7 +40,7 @@ export type MakeDifferenceOptional<TLeft, TRight> = Omit<
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// from https://stackoverflow.com/a/53955431
|
|
43
|
-
// eslint-disable-next-line
|
|
43
|
+
// eslint-disable-next-line ts/naming-convention
|
|
44
44
|
export type IsUnion<T, U extends T = T> = (
|
|
45
45
|
T extends any ? (U extends T ? false : true) : never
|
|
46
46
|
) extends false
|
|
@@ -152,7 +152,7 @@ export function replaceEqualDeep<T>(prev: any, _next: T): T {
|
|
|
152
152
|
let equalItems = 0
|
|
153
153
|
|
|
154
154
|
for (let i = 0; i < nextSize; i++) {
|
|
155
|
-
const key = array ? i : nextItems[i]
|
|
155
|
+
const key = array ? i : (nextItems[i] as any)
|
|
156
156
|
if (
|
|
157
157
|
((!array && prevItems.includes(key)) || array) &&
|
|
158
158
|
prev[key] === undefined &&
|
|
@@ -205,7 +205,7 @@ function hasObjectPrototype(o: any) {
|
|
|
205
205
|
return Object.prototype.toString.call(o) === '[object Object]'
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
export function isPlainArray(value: unknown) {
|
|
208
|
+
export function isPlainArray(value: unknown): value is Array<unknown> {
|
|
209
209
|
return Array.isArray(value) && value.length === Object.keys(value).length
|
|
210
210
|
}
|
|
211
211
|
|
|
@@ -315,23 +315,25 @@ export type ControlledPromise<T> = Promise<T> & {
|
|
|
315
315
|
resolve: (value: T) => void
|
|
316
316
|
reject: (value: any) => void
|
|
317
317
|
status: 'pending' | 'resolved' | 'rejected'
|
|
318
|
+
value?: T
|
|
318
319
|
}
|
|
319
320
|
|
|
320
|
-
export function createControlledPromise<T>(onResolve?: () => void) {
|
|
321
|
-
let resolveLoadPromise!: () => void
|
|
321
|
+
export function createControlledPromise<T>(onResolve?: (value: T) => void) {
|
|
322
|
+
let resolveLoadPromise!: (value: T) => void
|
|
322
323
|
let rejectLoadPromise!: (value: any) => void
|
|
323
324
|
|
|
324
|
-
const controlledPromise = new Promise<
|
|
325
|
+
const controlledPromise = new Promise<T>((resolve, reject) => {
|
|
325
326
|
resolveLoadPromise = resolve
|
|
326
327
|
rejectLoadPromise = reject
|
|
327
328
|
}) as ControlledPromise<T>
|
|
328
329
|
|
|
329
330
|
controlledPromise.status = 'pending'
|
|
330
331
|
|
|
331
|
-
controlledPromise.resolve = () => {
|
|
332
|
+
controlledPromise.resolve = (value: T) => {
|
|
332
333
|
controlledPromise.status = 'resolved'
|
|
333
|
-
|
|
334
|
-
|
|
334
|
+
controlledPromise.value = value
|
|
335
|
+
resolveLoadPromise(value)
|
|
336
|
+
onResolve?.(value)
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
controlledPromise.reject = (e) => {
|