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);2 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?