0

I'm writing a Link component with TypeScript, and am trying to achieve a typed API that supports the varying parameters that my app routes use.

I have some routes defined like this:

enum Routes {
  CONTACT = '/contact'
  PRODUCT = '/product/[productId]'
}

type RouteParams = {
  [Routes.CONTACT]: undefined;
  [Routes.PRODUCT]: {
    productId: string
  }
}

The Link component API is like this:

type LinkProps = React.FC<{ href: Routes, params?: {} }>

My question is, is it possible for params here to dynamically change to the correct type defined in RouteParams, based on the input href value?

For example:

<Link href={Routes.CONTACT} /> // correctly typed

<Link href={Routes.PRODUCT} params={{}} /> // error: missing 'productId' param
2
  • Why don’t you define the params as [k: string]: string; Commented Aug 9, 2020 at 15:49
  • Thank you for your comment, that would certainly be an improvement, but I don't believe it solves the question at hand here regarding dynamic types. Thanks again! Commented Aug 9, 2020 at 19:45

1 Answer 1

2

This is the best I can do, but it's castless and typechecks out :)

enum Routes {
  CONTACT = "/contact",
  PRODUCT = "/product/[productId]",
}

type RouteParams = {
  [Routes.CONTACT]: {};
  [Routes.PRODUCT]: {
    productId: string;
  };
};

function TLink<T extends Routes>({ href, ...p }: { href: T } & RouteParams[T]) {
  return <Link href={href} {...p} />;
}

function Component() {
  return (
    <Container>
      <TLink href={Routes.CONTACT} />
      <TLink href={Routes.PRODUCT} productId="42" />
    </Container>
  );
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! Your solution is exactly what I was looking for. I have updated the typing on the Link component example you provided like so: ``` const Link = <T extends keyof RouteParams>({ href, ...p }: { href: T } & { params?: RouteParams[T] }) => <NextLink href={href} {...p} />; ``` To achieve my desired API of passing the params in a specified prop. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.