Comments (11)
ToOptions wouldn't satisfy all the possible options that a <Link>
could take.
Try this.
import { LinkProps, Registered router } from "@tanstack/react-router"
interface MyLinkProps {
linkProps: LinkProps<RegisteredRouter['routeTree']>
}
...
<Link params {...props.linkProps}>
from router.
- LinkProps includes RegisteredRouter by default
export type LinkProps<TRouteTree extends AnyRoute = RegisteredRouter['routeTree'], TFrom ....
And it doesn't work either.
Type '{ children: ((string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | ((state: { ...; }) => ReactNode)) & (string | ... 4 more ... | ReactPortal)) | null | undefined; ... 287 more ...; onTransitionEndCapture?: TransitionEventHandler<...> | undefined; }' is not assignable to type 'IntrinsicAttributes & ({ to?: ToPathOption<Route<any, "/", "/", string, "__root__", RootSearchSchema, RootSearchSchema, RootSearchSchema, ... 12 more ..., any>, string, "/" | ... 3 more ... | "/posts/$id/"> | undefined; hash?: true | ... 1 more ... | undefined; state?: true | ... 1 more ... | undefined; from?: Route...'.
Type '{ children: ((string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | ((state: { ...; }) => ReactNode)) & (string | ... 4 more ... | ReactPortal)) | null | undefined; ... 287 more ...; onTransitionEndCapture?: TransitionEventHandler<...> | undefined; }' is not assignable to type 'MakePathParamOptions<true | ParamsReducer<{} | {} | { id: string; } | ({ id: string; } & {}), {} | {} | ({ id: string; } & {})>>'.
Types of property 'params' are incompatible.
Type 'true | ((current: {} | {} | { id: string; } | ({ id: string; } & {})) => never) | undefined' is not assignable to type 'true | ParamsReducer<{} | {} | { id: string; } | ({ id: string; } & {}), {} | {} | ({ id: string; } & {})>'.
Type 'undefined' is not assignable to type 'true | ParamsReducer<{} | {} | { id: string; } | ({ id: string; } & {}), {} | {} | ({ id: string; } & {})>'.
from router.
@schiller-manuel did anything change here? LinkProps used to work just fine.
from router.
Adding
{...toOptions}
from={"/"}
satisfies props.. But this will overwrite the "from"
from the toOptions
from router.
Not sure if it covers all your use-cases, but I was able to get a Link wrapper working with something like this. Personally I find it cleaner passing the whole route object as opposed to just the to
. That also allowed me to get by without having to pass a generic type to my custom Link component since typescript can directly infer it from the route
prop.
// helper types
type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
type ExcludeEmpty<T> = T extends AtLeastOne<T> ? T : never;
// seem to be as safe/strict as the props of the tanstack-provided Link component
type RouteParams<T extends AnyRoute = RegisteredRouter['routeTree']> = ExcludeEmpty<
T['types']['params']
> extends never
? { params?: never }
: { params: T['types']['params'] };
type RouteSearch<T extends AnyRoute = RegisteredRouter['routeTree']> = ExcludeEmpty<
T['types']['searchSchema']
> extends never
? { search?: never }
: {
search?: T['types']['searchSchema'] | ((args: T['types']['fullSearchSchema']) => T['types']['searchSchema']);
};
// component props
type MyLinkProps<T extends AnyRoute = RegisteredRouter['routeTree']> = {
route: T;
children: React.ReactNode;
className?: string;
disabled?: boolean;
} & RouteParams<T> &
RouteSearch<T>;
// custom Link component
function MyLink<T extends AnyRoute = RegisteredRouter['routeTree']>({
route,
children,
...other
}: MyLinkProps<T>) {
return (
<Link<AnyRoute> to={route?.to} {...other}>
{children}
</Link>
);
}
As a note - there might be a better way to skin this cat, but the docs seem to be pretty limited on the topic. Just figured I would share what worked for me in case you were still stuck here.
from router.
So turns out this is what works.
const MyLink = <
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
TFrom extends RoutePaths<TRouteTree> | string = string,
TTo extends string = '',
TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,
TMaskTo extends string = '',
>(
props: React.PropsWithoutRef<
LinkProps<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> &
Omit<React.HTMLProps<'a'>, 'children' | 'preload'>
>
) => <Link {...props} />
from router.
can we make use of this in createLink
?
I don't want to expose all of these generics as public API, otherwise we cannot modify them without causing breaking changes
from router.
So did anyone inspected - what's wrong with ToOptions? In my optinion - that is a user friendly type to be used in this place!
from router.
This code was working
type MenuItem = { label: string; route: LinkProps; };
const MENUS: MenuItem[] = [ { label: 'Test', route: { params: (old) => old, search: (old) => ({...old, test: true}), }, }];
But I updated from 1.16.6 to 1.20.1 and it does not work anymore. I got the error :
Type '{ params: (old: never) => never; search: (old: {}) => { test: boolean }; }' is not assignable to type 'LinkProps'. Property 'to' is missing in type '{ params: (old: never) => never; search: (old: {}) => { test: boolean }; }' but required in type 'CheckPathError<Route<any, "/", "/", string, "__root__", RootSearchSchema, RootSearchSchema, RootSearchSchema, RootSearchSchema, ... 11 more ..., any>>'.ts(2322) link.d.ts(72, 5): 'to' is declared here. Test.tsx(14, 3): The expected type comes from property 'route' which is declared here on type 'MenuItem'
from router.
I've seen many similar issues/discussions and stackoverflow posts. At this point, we could really use some official document / examples on how to wrap components in a type safe way. Even the customized solutions that work, only the to
prop is typed but things like search
and params
do not get type safety that match to
.
from router.
Yeah, this is basically the same as #1194. I proposed contributing a solution but there was no response from the maintainers at that time.
Here's the workaround I use currently:
(It uses a wrapper function to create the link options, so it can be used as a regular object. This also works for passing it into a component without requiring a ton of boilerplate generics everywhere.)
export type RouterLinkProps = Parameters<RegisteredRouter["navigate"]>[0];
/**
* Validate a router link as type-safe and return a generic {@link RouterLinkProps}.
* @example link({ to: "/view/$id", params: { id: "1" } })
*/
export function link<
TRouteTree extends AnyRoute = RegisteredRouter["routeTree"],
TFrom extends RoutePaths<TRouteTree> | string = string,
TTo extends string = "",
TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,
TMaskTo extends string = "",
>(options: UseLinkPropsOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>) {
return options as RouterLinkProps;
}
The type can also be spread directly:
const someLink = link({ .... });
...
function MyComponent({ someLink } : { someLink: RouterLinkProps }) {
return <Link {...someLink} />;
}
from router.
Related Issues (20)
- File based routing lazy-loading: when new build is pushed, lazy loaded scripts fail to load and causes an error HOT 8
- Can't update search using `Link` component without providing `to` prop HOT 5
- Layout Index Routes Don't Have Proper Id HOT 3
- Docs: incorrect useMatch argument description HOT 5
- Lazy routes are not generated on 1.19.3 version of router-vite-plugin HOT 2
- Issue with nested params after updating to the latest release when prefixed with `_` HOT 10
- Redirect in beforeLoad not working HOT 12
- Passing a function to Link's children property causing a type error
- Unexpected trailing slash causes mismatch between exact link active option and url HOT 6
- Can't use errorComponent in createLazyFileRoute HOT 7
- Vite Plugin Route file generation does not work while Vite is running on Windows machines HOT 8
- Dynamic route matching component error HOT 1
- Router does not trigger `loader` or `beforeLoad` when navigating to same url HOT 5
- Router's internal `state.location` is not updated when making manual changes to the url HOT 9
- The abortController from the loader function is not working HOT 1
- bad types in file link.d.ts HOT 11
- router errors keep around when navigating to a different route for `defaultPendingMs: 0`
- pending component is rendered for routes that have no loader
- HMR crash (under very specific circumstances) HOT 9
- The defaultPendingComponent is called twice on the first visit to the site. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from router.