router icon indicating copy to clipboard operation
router copied to clipboard

Overlapping Keys Cause Type Issues Using Experimental Intersection

Open rajbirjohar opened this issue 1 year ago • 0 comments

Describe the bug

We have three routes:

index.tsx

import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";

const indexFilters = z.object({
  search: z.string().catch("").optional(),
});

const IndexPage = () => {
  return <div>Index Page</div>;
};

type IndexPageProps = z.infer<typeof indexFilters>;

export const Route = createFileRoute("/")({
  component: IndexPage,
  validateSearch: (search: Record<string, unknown>): IndexPageProps =>
    indexFilters.parse(search),
});

about/index.tsx

import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";

const aboutFilters = z.object({
  limit: z.number().catch(10).optional(),
  materialTypes: z.array(z.string()).catch([]).optional(),
  // search: z.string().catch("").optional(),
});

const AboutPage = () => {
  return <div>About Page</div>;
};

export const Route = createFileRoute("/about/")({
  component: AboutPage,
  validateSearch: (
    search: Record<string, unknown>
  ): z.infer<typeof aboutFilters> => aboutFilters.parse(search),
});

contact/index.tsx

import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/contact/')({
  component: () => <div>Hello /contact/!</div>
})

components/Search/index.tsx

import { useSearch } from "@tanstack/react-router";

const Search = () => {
  const { search, limit, materialTypes } = useSearch({
    strict: false,
    experimental_returnIntersection: true,
  });

  return (
    <div>
      <h1>Search</h1>
      <pre>{JSON.stringify(search, null, 2)}</pre>
    </div>
  );
};

export default Search;

And a component that uses the useSearch hook with experimental_returnIntersection. If both index.tsx and about/index.tsx have overlapping schema fields, it causes the other non-overlapping fields to throw a type error saying that it does not belong on:

Property 'materialTypes' does not exist on type 'Partial<Omit<Partial<Reducer<Reducer<unknown, RootSearchSchema, UnionizeCollisions<unknown, RootSearchSchema>>, { search?: string | undefined; }, UnionizeCollisions<...>>>, "__TRootSearchSchema__">>'.

You can test this by uncommenting the search field in the about/index.tsx page.

Any non-overlapping fields which are accessed via the useSearch hook also might cause the opposite effect where an overlapping field does not exist in the error above.

My use case for using experimental_returnIntersection is for building a component that can manipulate common filters across multiple tables but not all pages have that filter. So inherently, some pages will have an empty object as their search parameter type.

Workaround: Use a single master schema for all pages that require it. Obviously defeats the purpose.

Your Example Website or App

https://github.com/rajbirjohar/tanstack-router-bug-demo

Steps to Reproduce the Bug or Issue

  1. Run repo locally.
  2. Check types of search, limit, materialTypes.
  3. Uncomment search schema field in about/index.tsx page.
  4. Check types again.

Expected behavior

It should not cause issues with overlapping schema fields.

Screenshots or Videos

No response

Platform

  • OS: MacOS, Windows
  • Browser: FF Dev, Chrome
  • Version: Latest

Additional context

No response

rajbirjohar avatar May 23 '24 22:05 rajbirjohar