Closed FrancoRATOVOSON closed 3 months ago
Hey @FrancoRATOVOSON, could you please share a StackBlitz example with your usage of shadcn/ui
and generouted
? I'd like to try adding the types in this context and make sure it works.
Hey @FrancoRATOVOSON, could you please share a StackBlitz example with your usage of
shadcn/ui
andgenerouted
? I'd like to try adding the types in this context and make sure it works.
https://stackblitz.com/edit/vitejs-vite-edpmge?file=src%2Fcomponents%2Flink.tsx
@FrancoRATOVOSON I've exported helper types to simplify the custom usage. I tried to access the StackBlitz demo, but seems broken at the moment — here's an example:
import { Link as RouterLink } from 'react-router-dom'
import { LinkProps } from '@generouted/react-router/client'
import { Params, Path } from '../../src/router'
type VariantProps = { variant: 'solid' | 'outline' }
export function Link<P extends Path>({ variant, ...props }: LinkProps<P, Params> & VariantProps) {
return (
<Button variant={variant}>
<RouterLink {...props} />
</Button>
)
}
;<Link to="/login" variant="solid">Login</Link>
;<Link to="/not-valid">Not valid</Link> // type-error
Hope that helps.
Just used this to add a NakedLink
component in my project that extends Link
and adds css
to remove default anchor styles. Super helpful! Thanks!
@FrancoRATOVOSON I've exported helper types to simplify the custom usage. I tried to access the StackBlitz demo, but seems broken at the moment — here's an example:
import { Link as RouterLink } from 'react-router-dom' import { LinkProps } from '@generouted/react-router/client' import { Params, Path } from '../../src/router' type VariantProps = { variant: 'solid' | 'outline' } export function Link<P extends Path>({ variant, ...props }: LinkProps<P, Params> & VariantProps) { return ( <Button variant={variant}> <RouterLink {...props} /> </Button> ) } ;<Link to="/login" variant="solid">Login</Link> ;<Link to="/not-valid">Not valid</Link> // type-error
Hope that helps.
This doesnt consider params and just past the to
given as props.
@FrancoRATOVOSON I'm not sure I understand what you mean, could you please elaborate on that?
Also, would be helpful if you provide a StackBlitz example as the previous one you shared seems broken.
@oedotme I wonder if you can provide an example of using the Link
from the generated router
file and extending that? I like the way that component takes a Path
and Params
, but I can't figure out how to customize it.
TLDR: Typescript error on line 20 https://stackblitz.com/edit/github-oenxul?file=src%2Fpages%2F_app.tsx
example:
import { Link, Path, Params } from "@/router";
import classNames from "classnames";
import type { LinkProps } from "@generouted/react-router/client";
export type NavigationItemProps<P extends Path> = LinkProps<P, Params> & {
active?: boolean;
linkClass?: string;
label: string;
icon: React.ReactNode;
};
export default function OpenNavigationItem<P extends Path>({ active = false, params, linkClass, icon, to }: NavigationItemProps<P>) {
return (
<Link
params={params}
to={to}
className={classNames(
"hover:!bg-gray-200 flex justify-center items-center h-14 w-14 rounded-full",
{ "bg-sys-brand-secondary-container": active },
linkClass
)}
>
{icon}
</Link>
);
}
I expected this to work, since it's just extending the LinkProps
type. instead I get:
error TS2322: Type '{ children: ReactNode; params: { sectionId: string; } | { sectionId: string; } | undefined; to: "/" | "/a" | "/b" | "/c" | ... 6 more ... | "/d/:id"; className: string; }' is not assignable to type 'IntrinsicAttributes & LinkProps<"/" | "/a" | "/b" | "/c" | "/d" | ... 5 more ... | "/e/:id", Params>'.
Types of property 'to' are incompatible.
Type '"/"' is not assignable to type '"/d/:id"'.
Sorry route names are obfuscated.
@briandunn @FrancoRATOVOSON As the params
prop is conditional, we'd need to pass all link props grouped.
Following the shorter example you've provided, this would fail:
const PrettyLink = <P extends Path>({ to, params }: LinkProps<P, Params>) => (
<Link to={to} params={params} data-pretty />
)
We should instead pass all props
directly:
const PrettyLink = <P extends Path>({ ...props }: LinkProps<P, Params>) => (
<Link {...props} data-pretty />
)
To combine other props with the Link
props — as the longer example, it seems that TypeScript infers props
differently when you destructure other props before ...props
:
type Props = { active: boolean }
const PrettyLink = <P extends Path>({ active, ...props }: Props & LinkProps<P, Params>) => {
return <Link {...props} data-pretty />
}
In this case instead, we can either use props.active
directly (which is my preference, that's why I haven't encounter issues extending the props 🙂) or destructure the external props later in the component:
type Props = { active: boolean }
const PrettyLink = <P extends Path>(props: Props & LinkProps<P, Params>) => {
// props.active | const { active } = props
return <Link {...props} data-pretty />
}
<PrettyLink to="/posts/:id" params={{ id: "xyz" }} /> ✅
Third possibility would be to allocate a namespace for original link props:
type Props = { active: boolean }
const PrettyLink = <P extends Path>({ active, link }: Props & { link: LinkProps<P, Params> }) => {
return <Link {...link} data-pretty />
}
<PrettyLink link={{ to: '/posts/:id', params: { id: 'xyz' } }} /> ✅
Hope that helps!
Closing for inactivity. Feel free to reopen if you guys still have problems with the types.
Sorry, discussion is not enabled in this repos so I opened an issue.
Context
I shadcn-ui for my app and I style my links the way it is explained in the (doc)[https://ui.shadcn.com/docs/components/button#as-child], here's the code :
As you can see, I had to import the link component from react-router-dom, because when I use the one provided by the
route.ts
file like this :I get a typescript error with the
{...props}
And yes, when I tried to see, if I :
const props: React.ComponentProps<typeof RouterLink>
, the type of props is indeed{ }
.So how can I extends my prop type to match the prop type of this component ?