i18next / next-i18next

The easiest way to translate your NextJs apps.
https://next.i18next.com
MIT License
5.65k stars 765 forks source link

8.0.2 types causing #995

Closed Cretezy closed 3 years ago

Cretezy commented 3 years ago

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

Expected behaviour

No error caused from the type casting.

OS

alexjamesmacpherson commented 3 years ago

I have also observed this, and other, type errors since upgrading to next-i18next@8.0.2:

$ tsc --noEmit

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/next-i18next/node_modules/react-i18next/src/index.d.ts:107:3
    107   i18n: i18n;
          ~~~~
    The expected type comes from property 'i18n' which is declared here on type 'IntrinsicAttributes & I18nextProviderProps & { children?: ReactNode; }'

node_modules/next-i18next/src/appWithTranslation.tsx:61:3 - error TS2322: Type '((props: AppProps) => Element) & NonReactStatics<ComponentType<any>, {}>' is not assignable to type 'ElementType<P>'.
  Type '((props: AppProps) => Element) & NonReactStatics<ComponentType<any>, {}>' is not assignable to type 'FunctionComponent<P>'.
    Types of parameters 'props' and 'props' are incompatible.
      Property 'pageProps' is missing in type 'Record<string, unknown> & { children?: ReactNode; }' but required in type 'AppProps'.

61   return hoistNonReactStatics(AppWithTranslation, WrappedComponent)
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  node_modules/next-i18next/src/appWithTranslation.tsx:13:3
    13   pageProps: SSRConfig
         ~~~~~~~~~
    'pageProps' is declared here.

node_modules/next-i18next/src/appWithTranslation.tsx:61:51 - error TS2345: Argument of type '"symbol" | "object" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | ... 159 more ... | FunctionComponent<...>' is not assignable to parameter of type 'ComponentType<any>'.
  Type '"symbol"' is not assignable to type 'ComponentType<any>'.

61   return hoistNonReactStatics(AppWithTranslation, WrappedComponent)
                                                     ~~~~~~~~~~~~~~~~

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/ku-search-fe/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; }'

Found 18 errors.
isaachinman commented 3 years ago

Hey @Cretezy and @alexjamesmacpherson – do either of you have steps to repro these type issues?

Check out this repo:

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

This is just the simple example, but using TypeScript. yarn build and npx tsc --noEmit both work fine. I assume this has something to do with your skipLibCheck compiler option?

Would be great if someone could fork the above repo and make the changes necessary to exhibit the issue.

Cretezy commented 3 years ago

This is my tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "downlevelIteration": true,
    "sourceMap": true
  },
  "exclude": ["node_modules"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

As for more code, I am using next-redux-wrapper:

export default appWithTranslation(wrapper.withRedux(RootApp));
isaachinman commented 3 years ago

@Cretezy If I copy/paste that tsconfig.json into the repo I linked above, yarn build && npx tsc --noEmit still runs just fine.

alexjamesmacpherson commented 3 years ago

@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 🤔

kachar commented 3 years ago

We also experience similar next build issues with the beta 8.0.2

https://github.com/daritelska-platforma/frontend/pull/78/checks?check_run_id=1990501530

Failed to compile.

./node_modules/next-i18next/src/appWithTranslation.tsx:2:34
Type error: Could not find a declaration file for module 'hoist-non-react-statics'. '/home/runner/work/frontend/frontend/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';`

  1 | import React from 'react'
> 2 | import hoistNonReactStatics from 'hoist-non-react-statics'
    |                                  ^
  3 | import { I18nextProvider } from 'react-i18next'
  4 | 
  5 | import { createConfig } from './config/createConfig'
error Command failed with exit code 1.

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": false,
    "checkJs": false,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "isolatedModules": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "jsx": "preserve",
    "baseUrl": "./src"
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", ".next"]
}

I'm reporting it here, but it might need dedicated issue at some point

isaachinman commented 3 years ago

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.

SeinopSys commented 3 years ago

@alexjamesmacpherson skipLibCheck only disables checking of *.d.ts declaration files, in this case the error is in a source file.

I'm still getting the issue in the first message, as well as the one in https://github.com/isaachinman/next-i18next/issues/995#issuecomment-786893130 with "strict": false. The latter I was able to solve by manually installing @types/hoist-non-react-statics in my project but the former seems to have no workaround for now - besides sticking with v8.0.1.

ianldgs commented 3 years ago

For now, my workaround is to ignore build errors.

ianldgs commented 3 years ago

@isaachinman I still have issues:

> next build

Failed to compile.

./node_modules/next-i18next/src/config/createConfig.ts:44:16
Type error: Property 'browser' does not exist on type 'Process'.

  42 |   }
  43 | 
> 44 |   if (!process.browser && typeof window === 'undefined') {
     |                ^
  45 |     combinedConfig.preload = locales
  46 | 
  47 |     const hasCustomBackend = userConfig?.use?.some((b) => b.type === 'backend')
info  - Creating an optimized production build .npm ERR! code 1

The true fix for this problem is to not include .ts code in the package anymore, and emitting proper declaration files, as I was doing in #1006. By including .ts files in the package we force typescript to build from the source, instead of including the already built code, for some reason.

isaachinman commented 3 years ago

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

kachar commented 3 years ago

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

yhbinariks commented 3 years ago

@isaachinman Still facing the types issue on v8.0.6

> tsc --noEmit

node_modules/next-i18next/src/config/createConfig.ts:44:16 - error TS2339: Property 'browser' does not exist on type 'Process'.
44   if (!process.browser && typeof window === 'undefined') {
                  ~~~~~~~
node_modules/next-i18next/src/config/defaultConfig.ts:16:20 - error TS2339: Property 'browser' does not exist on type 'Process'.
16     return process.browser && typeof window !== 'undefined'
                      ~~~~~~~

my tsconfig

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "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"
  ]
}
NiloDrumond commented 3 years ago

@isaachinman Still facing the types issue on v8.0.6

> tsc --noEmit

node_modules/next-i18next/src/config/createConfig.ts:44:16 - error TS2339: Property 'browser' does not exist on type 'Process'.
44   if (!process.browser && typeof window === 'undefined') {
                  ~~~~~~~
node_modules/next-i18next/src/config/defaultConfig.ts:16:20 - error TS2339: Property 'browser' does not exist on type 'Process'.
16     return process.browser && typeof window !== 'undefined'
                      ~~~~~~~

my tsconfig

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "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"
  ]
}

This might be relevant to this issue: https://stackoverflow.com/a/59562136

edit: in fact, browser isn't typed on NodeJS.Process at least in my @types/node version (14.14.10)

yhbinariks commented 3 years ago

@

@isaachinman Still facing the types issue on v8.0.6

> tsc --noEmit

node_modules/next-i18next/src/config/createConfig.ts:44:16 - error TS2339: Property 'browser' does not exist on type 'Process'.
44   if (!process.browser && typeof window === 'undefined') {
                  ~~~~~~~
node_modules/next-i18next/src/config/defaultConfig.ts:16:20 - error TS2339: Property 'browser' does not exist on type 'Process'.
16     return process.browser && typeof window !== 'undefined'
                      ~~~~~~~

my tsconfig

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "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"
  ]
}

This might be relevant to this issue: https://stackoverflow.com/a/59562136

edit: in fact, browser isn't typed on NodeJS.Process at least in my @types/node version (14.14.10)

Yes, but the process.browser is deprecated https://github.com/vercel/next.js/issues/5354#issuecomment-520305040 Btw @types/node is 14.14.22 in my project

Thomas0c commented 3 years ago

For anyone who might find this helpful. Adding a global.d.ts with the following content solves the issue of process.browser throwing an error.

declare namespace NodeJS {
  interface Process {
    browser: boolean;
  }
}
NiloDrumond commented 3 years ago

@

@isaachinman Still facing the types issue on v8.0.6

> tsc --noEmit

node_modules/next-i18next/src/config/createConfig.ts:44:16 - error TS2339: Property 'browser' does not exist on type 'Process'.
44   if (!process.browser && typeof window === 'undefined') {
                  ~~~~~~~
node_modules/next-i18next/src/config/defaultConfig.ts:16:20 - error TS2339: Property 'browser' does not exist on type 'Process'.
16     return process.browser && typeof window !== 'undefined'
                      ~~~~~~~

my tsconfig

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "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"
  ]
}

This might be relevant to this issue: https://stackoverflow.com/a/59562136 edit: in fact, browser isn't typed on NodeJS.Process at least in my @types/node version (14.14.10)

Yes, but the process.browser is deprecated vercel/next.js#5354 (comment) Btw @types/node is 14.14.22 in my project

Isn't this an easy fix of just removing this process.browser completely? It shouldn't affect anything as window covers the same purpose. I can't test it right now because I'm traveling, but I don't see why just removing these occurrences of process.browser and leaving only window wouldn't fix it. @isaachinman

isaachinman commented 3 years ago

cc @felixmosh

felixmosh commented 3 years ago

@NiloDrumond, I've tested it, typeof window check doesn't works (remains in the bundle) since it was implemented in Next.js using babel plugin (and not webpack.DefinePlugin), which doesn't run on node_modules by default.

Note, instead of adding the declaration file as suggested above, you can add the Next.js's global define

Note 2, you are using the src folder which is not part of the public api of this lib, therefore, in my opinion, it is not such a big deal to request PPL to add this in there tsconfig.json file.

The benefits of using process.browser are significant.

suarezph commented 2 years ago

Hi @isaachinman I am getting an error version 11.0

Type error: Argument of type '{ i18n: { defaultLocale: string; locales: string[]; localeDetection: boolean; }; backend: { backendOptions: { expirationTime: number; loadPath: string; allowMultiLoading: boolean; crossDomain: boolean; }[]; backends: any[]; }; debug: boolean; load: string; localePath: string; use: (typeof ChainedBackend)[]; }' is not assignable to parameter of type 'UserConfig'. Type '{ i18n: { defaultLocale: string; locales: string[]; localeDetection: boolean; }; backend: { backendOptions: { expirationTime: number; loadPath: string; allowMultiLoading: boolean; crossDomain: boolean; }[]; backends: any[]; }; debug: boolean; load: string; localePath: string; use: (typeof ChainedBackend)[]; }' is not assignable to type 'InitOptions'. Types of property 'load' are incompatible. Type 'string' is not assignable to type '"languageOnly" | "all" | "currentOnly" | undefined'.

Same implementation above!

code source ./src/pages/_app.tsx running npm run build. Please advise?

isaachinman commented 2 years ago

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