MetaFunction data type not inferred from clientLoader
cherewaty opened this issue · comments
Reproduction
https://stackblitz.com/edit/remix-run-remix-qggawd?file=app%2Froutes%2Fhello.tsx
System Info
System:
OS: macOS 14.4.1
CPU: (10) arm64 Apple M1 Pro
Memory: 249.42 MB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.10.0 - ~/.nvm/versions/node/v20.10.0/bin/node
Yarn: 4.1.1 - ~/.nvm/versions/node/v20.10.0/bin/yarn
npm: 10.2.3 - ~/.nvm/versions/node/v20.10.0/bin/npm
Browsers:
Chrome: 122.0.6261.94
Safari: 17.4.1
Used Package Manager
yarn
Expected Behavior
The docs for meta
describe a TypeScript-friendly approach for using loader
data in meta
: https://remix.run/docs/en/main/route/meta#data
I have a Remix app in SPA mode using clientLoader
s. I tried to take a similar approach to use typed clientLoader
data in meta
:
export async function clientLoader({ params }: ClientLoaderFunctionArgs) {
return { task: { name: "Hello" } };
}
export const meta: MetaFunction<typeof clientLoader> = ({ data }) => {
return [{ title: data.task.name }];
};
Actual Behavior
The code posted successfully passes the task
with name Hello
to meta
, and it gets applied to the document title in the browser. But TypeScript reports that 'data' is of type 'unknown'
inside of meta
.
I believe it's because the generic only allows to extends
from LoaderFunction
.
Yeah, also it makes sense.
You're rendering meta tags on the server, so in this case you should only rely on data provided by the loader.
Yeah, also it makes sense. You're rendering meta tags on the server, so in this case you should only rely on data provided by the loader.
This might not be the whole story since Remix also supports a SPA mode, I believe the meta function should work with clientLoader
as well.
I've got a clunky workaround in place that gets me correct type information for data
, but:
- doesn't add type protection for the return of
meta
, sinceMetaFunction
doesn't match - Requires importing a type from
@remix-run/node
, which feels conceptually wrong for SPA mode
import { SerializeFrom } from "@remix-run/node";
export const meta = ({ data }: { data: SerializeFrom<typeof clientLoader> }) => {
return [{ title: data.task.name }];
};