remix icon indicating copy to clipboard operation
remix copied to clipboard

MetaFunction doesn't take loader throwing errors/responses into account for data type

Open silvenon opened this issue 3 years ago • 0 comments

What version of Remix are you using?

1.7.4

Steps to Reproduce

  1. export a loader that conditionally throws an error or a response, but otherwise returns a JSON response
  2. export a meta function which is accessing a data property, use MetaFunction to obtain data type
  3. create an ErrorBoundary or CatchBoundary, depending on step 1
  4. satisfy the condition that causes loader to throw

This is my slightly contrived app/routes/item.$num.tsx, which ensures that the $num param is a valid number, otherwise throws an error:

import type { LoaderArgs, MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import invariant from "tiny-invariant";

export async function loader({ params }: LoaderArgs) {
  invariant(params.num, "num is required");
  const num = Number(params.num);
  invariant(!Number.isNaN(num), "num is not a number");
  return json({ num })
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
  return {
    title: `Item ${data.num}`,
  }
}

export default function Item() {
  const { num } = useLoaderData<typeof loader>()
  return (
    <h1>Item {num}</h1>
  )
}

export function ErrorBoundary({ error }: { error: Error }) {
  return (
    <div>
      <h1>Something went wrong</h1>
      <pre>{error.message}</pre>
    </div>
  )
}

Expected Behavior

I expected the data type in the meta function to stop me from unconditionally accessing data.num, assuming that data will always be an object.

Actual Behavior

The types in the meta function act like data will always be the object serialized from the loader, but in case the loader throws by accessing the root with an invalid $num, for example /item/foo, it will be undefined, so accessing data.num will throw an error.

silvenon avatar Oct 29 '22 23:10 silvenon