Closed lukebowerman closed 1 year ago
This is also relevant for usage in any custom handles, as libraries tend to provide a generics slot for the data type.
For example remix-utils exports a type for the handle called HandleStructuredData which expects a type of the data as the first argument.
Update: Or is it... 🤔 Data in a handle doesn't seem to be deserialised?
NOTE: The UseDataFunctionReturn
utility type simply returns the type of the JSON payload returned from your loader... from return typedjson(payload)
It doesn't actually convert the JSON data back to the native type (via metadata). If you look at the code for useTypedLoaderData
, it does the actual conversion via deserializeRemix()
useMatches
returns an array of active routes which includes the loader data. This loader data has NOT been deserialized. You will need to do that manually.
import { loader as rootLoader } from '~/root'
type RootLoaderData = UseDataFunctionReturn<typeof rootLoader>
const rootData = deserializeRemix<RootLoaderData>(useMatches()[0].data)
I plan on adding a useTypedRouteLoaderData
function that will wrap all this.
const rootData = useTypedRouteLoaderData<typeof rootLoader>("root")
NOTE: The UseDataFunctionReturn utility type simply returns the type of the JSON payload returned from your loader... from return typedjson(payload)
@kiliman That's a great point:
I wrote a simple hook within which I use UseDataFunctionReturn
:
const deserializeMatch = <LoaderType>(data: RouteData) =>
deserializeRemix<UseDataFunctionReturn<LoaderType>>(
data as RemixSerializedType<UseDataFunctionReturn<LoaderType>>
)
export const useMatchDeserialized = <LoaderType>(route: string) => {
const match = useMatches().find((m) => m.id === route)
if (!match) throw new Error(`Route not found for: ${route}`)
if (!match?.data) throw new Error(`Route "${route}" did not have data`)
const loaderData = deserializeMatch<LoaderType>(match.data)
if (!loaderData) throw new Error(`Route "${route}" could not be deserialized`)
return loaderData
}
I just realized look at this code that I also had to copy the RemixSerializedType
into my repo over to prevent a type issue with the deserializeRemix
input
declare type NonJsonTypes =
| 'date'
| 'set'
| 'map'
| 'regexp'
| 'bigint'
| 'undefined'
| 'infinity'
| '-infinity'
| 'nan'
| 'error'
declare type MetaType = Record<string, NonJsonTypes>
declare type RemixSerializedType<T> = {
__obj__: T | null
__meta__?: MetaType | null
} & (
| T
| {
__meta__?: MetaType
}
)
Would it make sense to export RemixSerializedType
as well or is there a way to accomplish that type-inference without doing so?
Went ahead and added RemixSerializedType
export as well
Thanks!
This has been published a v0.1.7
Related to conversation https://github.com/kiliman/remix-typedjson/issues/18 - exports the
UseDataFunctionReturn
type which makes typing aloader
response when consumed viauseMatches
and should be helpful in concert with theuseRouteLoaderData
function.