#Dynamic Route Typing

35 messages · Page 1 of 1 (latest)

brisk cave
#

Hey all, quick preface: I don't necessarily think this belongs in the help-forum, I would have preferred to put this in #discussions, but I don't have write permissions at the moment.

Here's my question/discussion:

In Next.js, we have dynamic routes, the basic example would be:

// /users/[userId]/page.tsx
export default function UserPage({
  params,
}: {
  params: { userId: string };
}) {}

But, let's say a userId is/should be a number, and not a string. Then I would go ahead and change the params type to:

params: { userId: number }

But, there is an odd caveat, which is that all params come in as strings (unless I'm mistaken), no matter what.

If I type params.userId to be a number, it's actually a string.

This makes sense, as routes are inherently strings, and I don't expect Next to handle the conversion for me, or even worse, make assumptions about the type and perform an automatic conversion.

But, how does this have implications on best practices? If I put number as the type, the code all works, and I get no linting errors.

Am I mistaken in assuming that this is problematic? Should a type exist that allows you to define what the params are but not their types to avoid confusion for users?

jolly hillBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

tulip tangle
brisk cave
#

Yeah, I guess I'm more concerned with the foot gun of typing a route param as something other than a string

#

I made a basic type to make my life less stressful for this, and to prevent any accidents across the app for my whole team

#
declare module "next" {
  type DynamicRouteParams<T extends string> = {
    params: {
      [K in T]: string;
    };
  };
}

Basic usage:

export default
 async function UserPage({
  params,
}: DynamicRouteParams<"userId">) {

I am personally of the opinion that a type like this should be exposed by default from next to prevent any misuse and incorrect typing.

viscid kelp
#

Web urls are all string based.
When you type your localhost/users/2 in a browser tab you enter it as string.
Next is only giving you the string value of your dynamic route!

If but you can override the type by using Number function

brisk cave
viscid kelp
#

I got your point to have a number instead of string but that the only case

#

You cannot type it as custom type or array

brisk cave
#

@viscid kelp I'd argue it's not, you could type a route param as a union like

params: { type: "test" | "hello" }

While in reality, that quote param could be anything

viscid kelp
#

Well for the DX that a cool stuff to have for sure!

brisk cave
#

Yeah, i don't think it's a huge deal, I'm definitely making more of it than it really is

#

But would be really nice if Next provided some typing / additional docs on that

viscid kelp
#

Yes but if you type it as union whats going on if you enter toto instead of test or hello? Is that a 404 or 500 ?

brisk cave
#

now I'm curious

#

let me try

viscid kelp
#

Because ts wont be happy because it does not match

brisk cave
#

Yeah, this is exactly what I'm concerned with:

// test/[testParam]/page.tsx

export default async function TestPage({
  params,
}: {
  params: { testParam: "foo" | "bar" };
}) {
  console.log(params);

  return <h1>{JSON.stringify(params)}</h1>;
}
#

Here is a very basic example

#

And in a perfect world, you'd think that testParams is either foo or bar, and other things would cause errors, etc

#

But that's not the case, testParam works no matter what I set it to on the route

#

It's prime for runtime errors, and the next docs mention nothing about that

#

Even just a simple "All params come in as a string, there is no enforcement of the types that you may set" would be such a good thing for them to note

viscid kelp
#

I guess its due to typing isnot supported here

brisk cave
#

Yeah, I mean I totally get why they all come in as strings

#

I just don't think that Next should then allow you to type them as whatever you'd hypothetically like

viscid kelp
#

I agree! I dont think Next should allow us to do it or we’ll found many issues

brisk cave
#

❤️ I'm glad I'm not alone

#

I think it's especially a problem on larger teams

#

If I have 12 people on my team, I can't expect all of them to know that params come in as indiscriminate strings

#

I just extended the next module (which I usually discourage) and added a "DynamicRouteParams" type that allows you to say the name of the route params, but no types, it will just set them to string (to match nextjs behavior)

#

like this:

new type

declare module "next" {
  type DynamicRouteParams<T extends string> = {
    params: {
      [K in T]: string;
    };
  };
}

Basic usage:

export default
 async function UserPage({
  params,
}: DynamicRouteParams<"userId">) {
still temple
#

You just need to remember that it is always string and not numbers or union of literal strings or whatever you can come up with. So you need to specify it as string and handle the conversion to the format you like manually.