T
TanStack8mo ago
rare-sapphire

Extracting Link props while retaining type safety

Hi, everyone. Need some help regarding utilizing router's typesafety in custom components. So as per docs, I was successfully able to create a custom link with same type safety as standard Link of tanstack. So far my code something like this:-
const BasicLinkComponent = forwardRef<HTMLAnchorElement, BasicLinkProps>(
(props, ref) => {
return <a ref={ref} {...props} />;
},
);

const CreatedLinkComponent = createLink(BasicLinkComponent);

export const CustomLink: LinkComponent<typeof BasicLinkComponent> = props => {
return (
<Headless.DataInteractive>
<CreatedLinkComponent {...props} />
</Headless.DataInteractive>
);
const BasicLinkComponent = forwardRef<HTMLAnchorElement, BasicLinkProps>(
(props, ref) => {
return <a ref={ref} {...props} />;
},
);

const CreatedLinkComponent = createLink(BasicLinkComponent);

export const CustomLink: LinkComponent<typeof BasicLinkComponent> = props => {
return (
<Headless.DataInteractive>
<CreatedLinkComponent {...props} />
</Headless.DataInteractive>
);
Now I want the same type safety in other components that internally use my CustomLink. Eg: PaginationPage But I am unable to extract CustomLink props type while retaining its type safety. If I try something like:
type CustomLinkProps = ComponentProps<typeof CustomLink>;
type CustomLinkProps = ComponentProps<typeof CustomLink>;
This doesn't enforce typing properly for 'to' & 'search' props. Any idea how to achieve this?
8 Replies
rare-sapphire
rare-sapphireOP8mo ago
Found this post on stackoverflow:- https://stackoverflow.com/questions/77788907/how-to-wrap-a-link-component-with-type-safety/77789323#77789323 I get that now we have createLink, so that should solve the creating custom component problem. But how do I deal with nested components & making it strongly typed on each layer. In my case its like:-
PaginationPage > LinkButton > CustomLink > Link (tanstack)
PaginationPage > LinkButton > CustomLink > Link (tanstack)
Eg in Pagination Page I want type safe to & search props like this:- to: /entities, search: { pageNo: 1 } // good. to: /entities, search: { foo: 1 } // bad to: /, search: { pageNo: 1 } // bad
Stack Overflow
How to wrap a Link component with type safety?
There is a Link component in @tanstack/react-router. I want to nest (wrap) this component into my own component(s). How can I do this and keep the type-safety which it provides? This is example of ...
environmental-rose
environmental-rose8mo ago
cc @Chris Horobin
rare-sapphire
rare-sapphireOP7mo ago
Can anyone help with this? @Chris Horobin I just want fully type safe to & search props in a custom component which internally uses a Link component. Thanks!
environmental-rose
environmental-rose7mo ago
can you please post a complete minimal example of what you have so far?
quickest-silver
quickest-silver7mo ago
If you don't use route masking or relative paths, props only need a single generic parameter to get the type inference.
type LinkProps<To extends string | undefined> = RouterLinkProps<
MyCustomElement,
RegisteredRouter,
string,
To
>
type LinkProps<To extends string | undefined> = RouterLinkProps<
MyCustomElement,
RegisteredRouter,
string,
To
>
And so any component that wraps your custom link can use those props. For example:
interface IWrapperComponent {
<const To extends string | undefined>(
props: LinkProps<To> & { foo: string },
): ReactNode
displayName?: string | undefined
}

const WrapperComponent: IWrapperComponent = ({ foo, ...props }) => {
// ...
return <Link {...props}>
}
interface IWrapperComponent {
<const To extends string | undefined>(
props: LinkProps<To> & { foo: string },
): ReactNode
displayName?: string | undefined
}

const WrapperComponent: IWrapperComponent = ({ foo, ...props }) => {
// ...
return <Link {...props}>
}
If you do use relative paths, you'll need 2 generic parameters (To and From) for RouterLinkProps, and if you use route masking it's more than that (don't remember off the top of my head). While this is not the easiest thing to manipulate, it's been working nicely for my codebase. Since we only have like 5 - 10 "link" components, all in the design system, it's not everyday that the devs have to deal with this.
rare-sapphire
rare-sapphireOP7mo ago
https://stackblitz.com/edit/tanstack-router-pzxewjeg?file=src%2Froutes%2Fposts.tsx You can checkout posts.tsx & pagination.tsx files. Here I want navigateFn of TablePagination to be strongly typed, just like the Tanstack Link component.
salmanbabri
StackBlitz
Strongly typed component using link internally - StackBlitz
Run official live example code for Router Basic File Based, created by Tanstack on StackBlitz
rare-sapphire
rare-sapphire7mo ago
There are some experimental type utilities which are not documented yet which solve use cases like this https://stackblitz.com/edit/tanstack-router-v8gzajq2?file=src%2Fpagination.tsx Its not documented yet because theres one or two things that need to be done
rare-sapphire
rare-sapphireOP7mo ago
That is exactly what I was looking for. Thanks a lot.

Did you find this page helpful?