next-i18next: 8.0.2 types causing

Describe the bug

Upgrading from 8.0.1 to 8.0.2 created an TypeScript:

app_1           | ./node_modules/next-i18next/src/appWithTranslation.tsx:61:3
app_1           | Type error: Type '((props: AppProps) => Element) & NonReactStatics<ComponentType<any>, {}>' is not assignable to type 'ComponentClass<P, any> | FunctionComponent<P> | (P extends SVGProps<SVGSymbolElement> ? "symbol" : never) | ... 173 more ... | (P extends SVGProps<...> ? "view" : never)'.
app_1           |   Type '((props: AppProps) => Element) & NonReactStatics<ComponentType<any>, {}>' is not assignable to type 'FunctionComponent<P>'.
app_1           |     Types of parameters 'props' and 'props' are incompatible.
app_1           |       Property 'pageProps' is missing in type 'Record<string, unknown> & { children?: ReactNode; }' but required in type 'AppProps'.
app_1           | 
app_1           |   59 |   }
app_1           |   60 | 
app_1           | > 61 |   return hoistNonReactStatics(AppWithTranslation, WrappedComponent)
app_1           |      |   ^
app_1           |   62 | }
app_1           |   63 | 

Occurs in next-i18next version

When moving from 8.0.1 to 8.0.2 (likely the type inclusion caused it).

Steps to reproduce

  • Can’t right now, can do over the weekend

Expected behaviour

No error caused from the type casting.

OS

  • Device: Linux, Ubuntu 20.10
  • Browser: N/A

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 11
  • Comments: 21 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Just want to say that all TS issues should be fixed from v8.0.6. You can see an example here of a next-i18next TypeScript app, with strict mode enabled:

https://github.com/isaachinman/next-i18next-typescript

OK, I think there are two steps to fixing this for users who have strict set to true:

  1. Set "strict": true in the next-i18next tsconfig and fix up all errors
  2. Move any necessary third-party typings from dev deps to prod deps

I have already begun work on the first item.

@isaachinman My tsconfig contains both "skipLibCheck": true and "exclude": ["node_modules"] - same as @Cretezy.

I’ve just cloned the repo you posted and played around with the tsconfig settings to reproduce the issue. Only change needed is to set strict to be true and all the below errors are presented:

next-i18next-typescript % yarn tsc --noEmit
yarn run v1.22.4
warning package.json: No license field
$ /Users/alex.macpherson/code/next-i18next-typescript/node_modules/.bin/tsc --noEmit
components/Header.tsx:3:26 - error TS7031: Binding element 'title' implicitly has an 'any' type.

3 export const Header = ({ title }) => (
                           ~~~~~

node_modules/next-i18next/src/appWithTranslation.tsx:2:34 - error TS7016: Could not find a declaration file for module 'hoist-non-react-statics'. '/Users/alex.macpherson/code/next-i18next-typescript/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/hoist-non-react-statics` if it exists or add a new declaration (.d.ts) file containing `declare module 'hoist-non-react-statics';`

2 import hoistNonReactStatics from 'hoist-non-react-statics'
                                   ~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/appWithTranslation.tsx:18:3 - error TS2322: Type 'null' is not assignable to type 'UserConfig'.
  Type 'null' is not assignable to type '{ i18n: NextJsI18NConfig; localeExtension?: string | undefined; localePath?: string | undefined; localeStructure?: string | undefined; serializeConfig: boolean; strictMode?: boolean | undefined; use?: any[] | undefined; }'.

18   configOverride: UserConfig = null,
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/appWithTranslation.tsx:51:9 - error TS2322: Type 'i18n | null' is not assignable to type 'i18n'.
  Type 'null' is not assignable to type 'i18n'.

51         i18n={i18n}
           ~~~~

  node_modules/react-i18next/src/ts4.1/index.d.ts:210:3
    210   i18n: i18n;
          ~~~~
    The expected type comes from property 'i18n' which is declared here on type 'IntrinsicAttributes & I18nextProviderProps & { children?: ReactNode; }'

node_modules/next-i18next/src/config/createConfig.ts:59:75 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type 'string | undefined' is not assignable to parameter of type '(substring: string, ...args: any[]) => string'.
      Type 'undefined' is not assignable to type '(substring: string, ...args: any[]) => string'.

59         const defaultLocaleStructure = localeStructure.replace('{{lng}}', lng).replace('{{ns}}', defaultNS)
                                                                             ~~~

  node_modules/typescript/lib/lib.es5.d.ts:454:5
    454     replace(searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string;
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The last overload is declared here.

node_modules/next-i18next/src/config/createConfig.ts:80:34 - error TS7006: Parameter 'p' implicitly has an 'any' type.

80         const getAllNamespaces = p => fs.readdirSync(p).map(file => file.replace(`.${localeExtension}`, ''))
                                    ~

node_modules/next-i18next/src/config/createConfig.ts:80:61 - error TS7006: Parameter 'file' implicitly has an 'any' type.

80         const getAllNamespaces = p => fs.readdirSync(p).map(file => file.replace(`.${localeExtension}`, ''))
                                                               ~~~~

node_modules/next-i18next/src/config/createConfig.ts:110:9 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'UserConfig'.
  No index signature with a parameter of type 'string' was found on type 'UserConfig'.

110     if (userConfig[obj]) {
            ~~~~~~~~~~~~~~~

node_modules/next-i18next/src/config/createConfig.ts:111:7 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ defaultLocale: string; locales: string[]; localeExtension: string; localePath: string; localeStructure: string; serializeConfig: boolean; strictMode: boolean; use: any[] | never[]; debug?: boolean | undefined; ... 46 more ...; errorStackTraceLimit: number; }'.
  No index signature with a parameter of type 'string' was found on type '{ defaultLocale: string; locales: string[]; localeExtension: string; localePath: string; localeStructure: string; serializeConfig: boolean; strictMode: boolean; use: any[] | never[]; debug?: boolean | undefined; ... 46 more ...; errorStackTraceLimit: number; }'.

111       combinedConfig[obj] = {
          ~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/config/createConfig.ts:112:12 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ defaultNS: string; errorStackTraceLimit: number; i18n: { defaultLocale: string; locales: string[]; }; readonly initImmediate: boolean; interpolation: { escapeValue: boolean; format: (value: string, format: string) => string; formatSeparator: string; }; ... 7 more ...; use: never[]; }'.
  No index signature with a parameter of type 'string' was found on type '{ defaultNS: string; errorStackTraceLimit: number; i18n: { defaultLocale: string; locales: string[]; }; readonly initImmediate: boolean; interpolation: { escapeValue: boolean; format: (value: string, format: string) => string; formatSeparator: string; }; ... 7 more ...; use: never[]; }'.

112         ...defaultConfig[obj],
               ~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/config/createConfig.ts:113:12 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ defaultLocale: string; locales: string[]; localeExtension: string; localePath: string; localeStructure: string; serializeConfig: boolean; strictMode: boolean; use: any[] | never[]; debug?: boolean | undefined; ... 46 more ...; errorStackTraceLimit: number; }'.
  No index signature with a parameter of type 'string' was found on type '{ defaultLocale: string; locales: string[]; localeExtension: string; localePath: string; localeStructure: string; serializeConfig: boolean; strictMode: boolean; use: any[] | never[]; debug?: boolean | undefined; ... 46 more ...; errorStackTraceLimit: number; }'.

113         ...combinedConfig[obj],
               ~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/config/createConfig.ts:114:12 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'UserConfig'.
  No index signature with a parameter of type 'string' was found on type 'UserConfig'.

114         ...userConfig[obj],
               ~~~~~~~~~~~~~~~

node_modules/next-i18next/src/createClient/node.ts:2:30 - error TS7016: Could not find a declaration file for module 'i18next-fs-backend/cjs'. '/Users/alex.macpherson/code/next-i18next-typescript/node_modules/i18next-fs-backend/cjs/index.js' implicitly has an 'any' type.

2 import i18nextFSBackend from 'i18next-fs-backend/cjs'
                               ~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/createClient/node.ts:16:5 - error TS2532: Object is possibly 'undefined'.

16     config.use.forEach(x => instance.use(x))
       ~~~~~~~~~~

node_modules/next-i18next/src/createClient/node.ts:19:28 - error TS2454: Variable 'initPromise' is used before being assigned.

19   return { i18n: instance, initPromise }
                              ~~~~~~~~~~~

node_modules/next-i18next/src/serverSideTranslations.ts:14:3 - error TS2322: Type 'null' is not assignable to type 'UserConfig'.
  Type 'null' is not assignable to type '{ i18n: NextJsI18NConfig; localeExtension?: string | undefined; localePath?: string | undefined; localeStructure?: string | undefined; serializeConfig: boolean; strictMode?: boolean | undefined; use?: any[] | undefined; }'.

14   configOverride: UserConfig = null,
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/serverSideTranslations.ts:62:7 - error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  No index signature with a parameter of type 'string' was found on type '{}'.

62       initialI18nStore[locale][ns] = (
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/next-i18next/src/serverSideTranslations.ts:72:7 - error TS2322: Type 'UserConfig | null' is not assignable to type 'UserConfig'.
  Type 'null' is not assignable to type 'UserConfig'.
    Type 'null' is not assignable to type '{ i18n: NextJsI18NConfig; localeExtension?: string | undefined; localePath?: string | undefined; localeStructure?: string | undefined; serializeConfig: boolean; strictMode?: boolean | undefined; use?: any[] | undefined; }'.

72       userConfig: config.serializeConfig ? userConfig : null,
         ~~~~~~~~~~

  node_modules/next-i18next/types.d.ts:53:5
    53     userConfig: UserConfig
           ~~~~~~~~~~
    The expected type comes from property 'userConfig' which is declared here on type '{ initialI18nStore: any; initialLocale: string; userConfig: UserConfig; }'

pages/_app.tsx:3:18 - error TS7031: Binding element 'Component' implicitly has an 'any' type.

3 const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
                   ~~~~~~~~~

pages/_app.tsx:3:29 - error TS7031: Binding element 'pageProps' implicitly has an 'any' type.

3 const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />
                              ~~~~~~~~~

pages/index.tsx:42:40 - error TS7031: Binding element 'locale' implicitly has an 'any' type.

42 export const getStaticProps = async ({ locale }) => ({
                                          ~~~~~~

pages/second-page.tsx:30:40 - error TS7031: Binding element 'locale' implicitly has an 'any' type.

30 export const getStaticProps = async ({ locale }) => ({
                                          ~~~~~~


Found 22 errors.

Here’s the offending tsconfig from that repo for clarity:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

That said, I’m not sure why my own project isn’t adhering to the skipLibCheck rule and throwing these errors from next-i18next@8.0.2 🤔

@aaesis You probably need to use as const. Next time please post questions on StackOverflow.

@isaachinman Indeed it seems to be fixed with v8.0.6! Works on our project flawlessly 🎉

For now, my workaround is to ignore build errors.