Layout params union types casted to string..
Unanswered
Couch's Kingbird posted this in #help-forum
Couch's KingbirdOP
Build is failing because next js cast union type to string.
Types of property 'params' are incompatible.
Type 'Promise<{ locale: string; }>' is not assignable to type 'Promise<{ locale: "fr" | "nl" | "en"; }>'.
Types of property 'params' are incompatible.
Type 'Promise<{ locale: string; }>' is not assignable to type 'Promise<{ locale: "fr" | "nl" | "en"; }>'.
export const dynamicParams = false;
export async function generateStaticParams(): Promise<{ locale: Locale }[]> {
return i18n.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({children, params}: {
children: React.ReactNode;
params: Promise<{ locale: Locale }>;
}) {
const { locale } = await params;
const { tr, dict } = await getTranslations(locale);8 Replies
@Couch's Kingbird Build is failing because next js cast union type to string.
Types of property 'params' are incompatible.
Type 'Promise<{ locale: string; }>' is not assignable to type 'Promise<{ locale: "fr" | "nl" | "en"; }>'.
js
export const dynamicParams = false;
export async function generateStaticParams(): Promise<{ locale: Locale }[]> {
return i18n.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({children, params}: {
children: React.ReactNode;
params: Promise<{ locale: Locale }>;
}) {
const { locale } = await params;
const { tr, dict } = await getTranslations(locale);
I wasn’t able to replicate that. For me it works like that. Can you provide a reproduction repo so we can have a look at it in detail?
Couch's KingbirdOP
Thanks for checking. Here's a minimal reproduction:
https://github.com/Tiktak-dev/nextjs-params-error
Created with
fails type checking with two errors.
Two things probably explain why it worked for you.
1. It only reproduces with
implies — and
parameter types checked contravariantly, so the narrowed
rejected. With it off, bivariance accepts the narrowing. On my real project:
7 errors with strict, 4 without, and the 5 that disappear are all layouts.
2. A page declaring the exact same narrowed
all — only layouts do. The generated contracts differ:
default: React.ComponentType<{ params: Promise<ParamMap[Route]> } & any> // AppPageConfig
default: React.ComponentType<LayoutProps<Route>> // LayoutConfig
The page contract is intersected with
page params are effectively never validated. Layouts are validated strictly.
That also explains the asymmetry noted in #82820 ("for layouts and routes,
but not for the pages"), which was closed and locked without a cause being
identified.
So if you tested a page, or a project without strict mode, it would look
fine. Could you try the repo with the layout?
https://github.com/Tiktak-dev/nextjs-params-error
Created with
create-next-app defaults, four files added. npm run buildfails type checking with two errors.
Two things probably explain why it worked for you.
1. It only reproduces with
strictFunctionTypes on, which strict: trueimplies — and
strict: true is the create-next-app default. It makesparameter types checked contravariantly, so the narrowed
Locale union isrejected. With it off, bivariance accepts the narrowing. On my real project:
7 errors with strict, 4 without, and the 5 that disappear are all layouts.
2. A page declaring the exact same narrowed
params produces no error atall — only layouts do. The generated contracts differ:
default: React.ComponentType<{ params: Promise<ParamMap[Route]> } & any> // AppPageConfig
default: React.ComponentType<LayoutProps<Route>> // LayoutConfig
The page contract is intersected with
any, which absorbs any mismatch, sopage params are effectively never validated. Layouts are validated strictly.
That also explains the asymmetry noted in #82820 ("for layouts and routes,
but not for the pages"), which was closed and locked without a cause being
identified.
So if you tested a page, or a project without strict mode, it would look
fine. Could you try the repo with the layout?
@Couch's Kingbird Thanks for checking. Here's a minimal reproduction:
https://github.com/Tiktak-dev/nextjs-params-error
Created with `create-next-app` defaults, four files added. `npm run build`
fails type checking with two errors.
Two things probably explain why it worked for you.
1. It only reproduces with `strictFunctionTypes` on, which `strict: true`
implies — and `strict: true` is the create-next-app default. It makes
parameter types checked contravariantly, so the narrowed `Locale` union is
rejected. With it off, bivariance accepts the narrowing. On my real project:
7 errors with strict, 4 without, and the 5 that disappear are all layouts.
2. A *page* declaring the exact same narrowed `params` produces no error at
all — only layouts do. The generated contracts differ:
default: React.ComponentType<{ params: Promise<ParamMap[Route]> } & any> // AppPageConfig
default: React.ComponentType<LayoutProps<Route>> // LayoutConfig
The page contract is intersected with `any`, which absorbs any mismatch, so
page params are effectively never validated. Layouts are validated strictly.
That also explains the asymmetry noted in #82820 ("for layouts and routes,
but not for the pages"), which was closed and locked without a cause being
identified.
So if you tested a page, or a project without strict mode, it would look
fine. Could you try the repo with the layout?
alr, I fixed your issue. The commit is currently pending, as I am not allowed to push to the repo. I'll delete the repo in 2 days from my PC if you dont answer.
in general: nextjs types params always as string instead of a literal. So you need to assert it first and only when you do that, you got typesafety on your side
in general: nextjs types params always as string instead of a literal. So you need to assert it first and only when you do that, you got typesafety on your side
Couch's KingbirdOP
Whenever you get a chance — feel free to open a PR from your fork, or just paste the diff here. Also, is it a patch on Next itself, or a workaround in the repro? Asking because the issue is about the validator rejecting the union, not about the assertion workaround.
@Couch's Kingbird Whenever you get a chance — feel free to open a PR from your fork, or just paste the diff here. Also, is it a patch on Next itself, or a workaround in the repro? Asking because the issue is about the validator rejecting the union, not about the assertion workaround.
PR is ready: https://github.com/Tiktak-dev/nextjs-params-error/pull/1
Its not about an issue from nextjs side. Its an issue from your understanding side
Its not about an issue from nextjs side. Its an issue from your understanding side
Couch's KingbirdOP
Thanks for taking the time. That's the workaround I'm already using in production though — the issue isn't about making it compile. It's that the generated ParamMap derives from the folder name and ignores what generateStaticParams returns, so the validator rejects a type the framework already guarantees under dynamicParams = false.
Vercel's triage read it the same way and opened a failing regression test for it: https://github.com/vercel-labs/next.js/pull/122
Closing this one, but thanks anyway.
Vercel's triage read it the same way and opened a failing regression test for it: https://github.com/vercel-labs/next.js/pull/122
Closing this one, but thanks anyway.
@Couch's Kingbird Thanks for taking the time. That's the workaround I'm already using in production though — the issue isn't about making it compile. It's that the generated ParamMap derives from the folder name and ignores what generateStaticParams returns, so the validator rejects a type the framework already guarantees under dynamicParams = false.
Vercel's triage read it the same way and opened a failing regression test for it: https://github.com/vercel-labs/next.js/pull/122
Closing this one, but thanks anyway.
yea I saw the one too and still the param there will be a string. And no, even when dynamicParams = false, it wont be validated on nextjs side. You are responsible for that
@Couch's Kingbird solved?