dynamic route param type mismatch
Unanswered
Tundra Swan posted this in #help-forum
Tundra SwanOP
Say I have a route handler at
where
This used to compile just fine in next 15.4. I have, however, recently upgraded to 15.5 and this no longer compiles when running
Is this expected behaviour in 15.5? Is there any way to opt out of this or otherwise get the 15.4 behaviour without actually downgrading?
my-app/app/api/[resourceId]/route.ts
with something like this:type Params = Promise<{ resourceId: Resource["id"] }>
export async function PATCH(request: NextRequest, ctx: { params: Params }) {
[...]
}
where
Resource["id"]
is a branded type: string & BRAND<"ResourceId">
This used to compile just fine in next 15.4. I have, however, recently upgraded to 15.5 and this no longer compiles when running
next build
:Type '{ params: Promise<{ resourceId: string; }>; }' is not assignable to type '{ params: Promise<{ resourceId: string & BRAND<"ResourceId">; }>; }'.
Is this expected behaviour in 15.5? Is there any way to opt out of this or otherwise get the 15.4 behaviour without actually downgrading?
17 Replies
@Tundra Swan Say I have a route handler at `my-app/app/api/[resourceId]/route.ts` with something like this:
ts
type Params = Promise<{ resourceId: Resource["id"] }>
export async function PATCH(request: NextRequest, ctx: { params: Params }) {
[...]
}
where `Resource["id"]` is a branded type: `string & BRAND<"ResourceId">`
This used to compile just fine in next 15.4. I have, however, recently upgraded to 15.5 and this no longer compiles when running `next build`:
Type '{ params: Promise<{ resourceId: string; }>; }' is not assignable to type '{ params: Promise<{ resourceId: string & BRAND<"ResourceId">; }>; }'.
Is this expected behaviour in 15.5? Is there any way to opt out of this or otherwise get the 15.4 behaviour without actually downgrading?
Interesting find. what is BRAND<"ResourceId"> ?
i think they made it stricter in 15.5
i think they made it stricter in 15.5
Tundra SwanOP
it's a branded type
think of it like this:
the idea behind branded types is to distinguish between structurally identical types at the type level
https://egghead.io/blog/using-branded-types-in-typescript
think of it like this:
type Brand<K, T> = K & { __brand: T }
type ResourceId = Brand<string, "ResourceId ">
the idea behind branded types is to distinguish between structurally identical types at the type level
https://egghead.io/blog/using-branded-types-in-typescript
@Tundra Swan it's a branded type
think of it like this:
type Brand<K, T> = K & { __brand: T }
type ResourceId = Brand<string, "ResourceId ">
the idea behind branded types is to distinguish between structurally identical types at the type level
https://egghead.io/blog/using-branded-types-in-typescript
yes but what is BRAND<"ResourceId"> ?
like what is it defined as in your code
Brand requires 2 generic types but yours only used one
sorry im having trouble understanding with the problem
Tundra SwanOP
it's a type helper from zod which basically does the same
ultimately, the problem is that i'm passing the branded type to the route handler param but next 15.5 expects a simple string in its autogenerated route typings
at least that's what i gather from the error msg:
ultimately, the problem is that i'm passing the branded type to the route handler param but next 15.5 expects a simple string in its autogenerated route typings
at least that's what i gather from the error msg:
Type '{ params: Promise<{ resourceId: string; }>; }' is not assignable to type '{ params: Promise<{ resourceId: string & BRAND<"ResourceId">; }>; }'.
so.. BRAND<"ResourceId"> is { __brand: "ResourceId" } ?
im not sure why you need to modify the type of the route handler param differently as doing
string & { __brand: "ResourceId" }
is different than just string
next will throw a type error since it is incompatible
Tundra SwanOP
well that's the point, it hasn't up until 15.5
have you tried adding
//@ts-ignore
above iti dont think theres specific config to disable this specific feature as these strict type checks are designed to make dev safer
there is this
moreover, i dont think you should be branding params if im reading the article right
Tundra SwanOP
yeah, i'd rather not lose all safety here
i do understand the issue, my only real gripe is that it seems to be a breaking change introduced in a minor version
this worked fine in 15.4
the change must have been introduced in 15.5
i also have some ideas on how to work around it... i could refactor the params to be non-branded types and then validate them inside the handlers... but i've got tons and tons of these already and i wanted to avoid doing this "by hand" (i mean, i would get some AI to do it but it would still have to be double checked)
i do understand the issue, my only real gripe is that it seems to be a breaking change introduced in a minor version
this worked fine in 15.4
the change must have been introduced in 15.5
i also have some ideas on how to work around it... i could refactor the params to be non-branded types and then validate them inside the handlers... but i've got tons and tons of these already and i wanted to avoid doing this "by hand" (i mean, i would get some AI to do it but it would still have to be double checked)
i could refactor the params to be non-branded types and then validate them inside the handlers...i would definetly do that since the params are unsafe parameters and is best practice to be treated with caution