Repository: remix-run/react-router
File: packages/react-router/lib/dom/ssr/routeModules.ts (TypeScript)

Code before:

/**
 * Optional, root-only `<Route Layout>` component to wrap the root content in.
 * Useful for defining the <html>/<head>/<body> document shell shared by the
 * Component, HydrateFallback, and ErrorBoundary
 */
export type LayoutComponent = ComponentType<{
  children: ReactElement<
    unknown,
    ErrorBoundaryComponent | HydrateFallbackComponent | RouteComponent
  >;
}>;

/**
 * A function that defines `<link>` tags to be inserted into the `<head>` of
 * the document on route transitions.
 *
 * @see https://remix.run/route/meta
 */
export interface LinksFunction {
  (): LinkDescriptor[];
}

export interface MetaMatch<
  RouteId extends string = string,
  Loader extends LoaderFunction | ClientLoaderFunction | unknown = unknown
> {
  id: RouteId;
  pathname: DataRouteMatch["pathname"];
  data: Loader extends LoaderFunction | ClientLoaderFunction
    ? DeprecatedSerializeFrom<Loader>
    : unknown;
  handle?: RouteHandle;
  params: DataRouteMatch["params"];
  meta: MetaDescriptor[];
  error?: unknown;
}

export type MetaMatches<
  MatchLoaders extends Record<
    string,
    LoaderFunction | ClientLoaderFunction | unknown
  > = Record<string, unknown>
> = Array<
  {
    [K in keyof MatchLoaders]: MetaMatch<
      Exclude<K, number | symbol>,
      MatchLoaders[K]
    >;
  }[keyof MatchLoaders]
>;

Review comment (suggestion):
I noticed during testing that I'm not sure we ever handled `meta` types for `clientLoader`.  I think as long as we always union with `undefined` this should be valid since `meta` would have no data on initial render for `clientLoader`-only routes.

Hybrid routes are trickier because `meta` would have data for the server loader on SSR, and on initial hydration and then would have `clientLoader` data subsequently - but I think that's just a userland solution via `MetaFunction<typeof loader | typeof clientLoader>`

Code after:

/**
 * Optional, root-only `<Route Layout>` component to wrap the root content in.
 * Useful for defining the <html>/<head>/<body> document shell shared by the
 * Component, HydrateFallback, and ErrorBoundary
 */
export type LayoutComponent = ComponentType<{
  children: ReactElement<
    unknown,
    ErrorBoundaryComponent | HydrateFallbackComponent | RouteComponent
  >;
}>;

/**
 * A function that defines `<link>` tags to be inserted into the `<head>` of
 * the document on route transitions.
 *
 * @see https://remix.run/route/meta
 */
export interface LinksFunction {
  (): LinkDescriptor[];
}

export interface MetaMatch<
  RouteId extends string = string,
  Loader extends LoaderFunction | ClientLoaderFunction | unknown = unknown
> {
  id: RouteId;
  pathname: DataRouteMatch["pathname"];
  data: Loader extends LoaderFunction | ClientLoaderFunction
    ? SerializeFrom<Loader>
    : unknown;
  handle?: RouteHandle;
  params: DataRouteMatch["params"];
  meta: MetaDescriptor[];
  error?: unknown;
}

export type MetaMatches<
  MatchLoaders extends Record<
    string,
    LoaderFunction | ClientLoaderFunction | unknown
  > = Record<string, unknown>
> = Array<
  {
    [K in keyof MatchLoaders]: MetaMatch<
      Exclude<K, number | symbol>,
      MatchLoaders[K]
    >;
  }[keyof MatchLoaders]
>;