You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next 13 + React 18 构建时createContext类型错误排查与解决

Next 13 + React 18 上下文类型检查错误修复方案

错误信息

Type error: Type 'OmitWithTag<typeof import("....calculator/page"), "metadata" | "default" | "config" | "generateStaticParams" | "revalidate" | ... 6 more ... | "generateMetadata", "">' does not satisfy the constraint '{ [x: string]: never; }'. Property 'ActiveTabContext' is incompatible with index signature. Type 'Context<ActiveTab>' is not assignable to type 'never'.

问题代码

type ActiveTab = [string, Dispatch<SetStateAction<string>>]
type SelectValues = [IApiCostsState[], Dispatch<SetStateAction<IApiCostsState[]>>]
type SumState = [number, Dispatch<SetStateAction<number>>]
type HelperState = [Helper, Dispatch<SetStateAction<Helper>>]

export const ActiveTabContext = createContext<ActiveTab>(['', () => { }]) as Context<ActiveTab>;;
export const SelectValuesContext = createContext<SelectValues>([setInitial(Object.keys(_apiCostsMock)[0]), () => { }]);
export const TotalSumContext = createContext<SumState>([0, () => { }]);
export const HelperContext = createContext<HelperState>([{index:-1}, () => { }]);
export const WindowWidthContext = createContext<number>(0);
export const ScrollElementContext = createContext<MutableRefObject<HTMLDivElement | null> | null>(null);

原因分析

Next.js 13的App Router对page.tsx和layout.tsx的导出有严格约束:这些文件只能导出Next官方允许的内容(比如默认组件、metadata、generateStaticParams等)。如果在这些文件中导出Context这类自定义变量,TypeScript会触发类型检查错误——因为Next要求这些文件的额外导出必须符合{ [x: string]: never; }(即不能有任何额外导出),而Context类型显然不满足这个要求。

修复步骤

  • 分离Context定义:创建单独的文件存放Context(比如app/calculator/contexts.ts),把所有Context的类型定义和创建逻辑移到这个文件中:
// app/calculator/contexts.ts
import { createContext, Dispatch, SetStateAction, MutableRefObject } from 'react';
import { IApiCostsState, Helper } from './your-types-file'; // 替换为你的类型文件路径
import { setInitial } from './your-utils-file'; // 替换为你的工具函数路径
import _apiCostsMock from './your-mock-file'; // 替换为你的mock文件路径

type ActiveTab = [string, Dispatch<SetStateAction<string>>]
type SelectValues = [IApiCostsState[], Dispatch<SetStateAction<IApiCostsState[]>>]
type SumState = [number, Dispatch<SetStateAction<number>>]
type HelperState = [Helper, Dispatch<SetStateAction<Helper>>]

export const ActiveTabContext = createContext<ActiveTab>(['', () => { }]);
export const SelectValuesContext = createContext<SelectValues>([setInitial(Object.keys(_apiCostsMock)[0]), () => { }]);
export const TotalSumContext = createContext<SumState>([0, () => { }]);
export const HelperContext = createContext<HelperState>([{index:-1}, () => { }]);
export const WindowWidthContext = createContext<number>(0);
export const ScrollElementContext = createContext<MutableRefObject<HTMLDivElement | null> | null>(null);
  • 清理page/layout文件的导出:在page.tsx或layout.tsx中,只保留Next允许的导出项(比如默认组件、metadata),通过import导入需要的Context:
// app/calculator/page.tsx
import { ActiveTabContext, SelectValuesContext } from './contexts';

export default function CalculatorPage() {
  // 使用Context的逻辑
  return <div>...</div>;
}

// 只保留Next允许的导出,比如metadata(如果需要)
export const metadata = {
  title: '计算器页面',
};
  • 移除不必要的类型断言:原代码中as Context<ActiveTab>是多余的,createContext<T>会自动返回Context<T>类型,无需额外断言;同时注意移除多余的分号(比如as Context<ActiveTab>;;中的两个分号)。

内容的提问来源于stack exchange,提问作者Илья Дуванов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:23:28