Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

i18next: No overload matches this call when calling getFixedT function

I'm using the i18next library in a TS app (not React) and getting an unexpected Typescript error.

I'm getting a type mismatch when calling the getFixedT function. I'm passing strings for both lng and ns, yet getting errors expecting null.

To Reproduce

I have the following type definition in i18next.d.ts:

// i18next.d.ts
import "i18next";
import definitions from "../i18n/locales/definitions/en.json";
import errors from "../i18n/locales/errors/en.json";

const NAMESPACES = {
  definitions: "definitions",
  errors: "errors",
};

declare module "i18next" {
    interface CustomTypeOptions {
        ns: typeof NAMESPACES.errors | typeof NAMESPACES.definitions;
        returnNull: false;
        resources: {
            en: {
                definitions: typeof definitions;
                errors: typeof errors;
            }
        };
    }
}

My resource files are defined by namespace, like so:

// src/i18n/locales/resources.ts
import definitions_de from './definitions/de.json';
import definitions_en from './definitions/en.json';
import errors_de from './errors/de.json';
import errors_en from './errors/en.json';

export const resources = {
    de: {
        definitions: definitions_de,
        errors: errors_de,
    },
    en: {
        definitions: definitions_en,
        errors: errors_en,
    },
        // <etc>
}

I init i18nInstance and export it here:

// src/i18n/index.ts
import i18n, { createInstance, InitOptions } from 'i18next';
import { fallbackLng, NAMESPACES } from '../constants';
import { resources } from './locales/resources';

const i18nInstance = createInstance();

void i18nInstance
    .init({
        fallbackLng, // use en if detected language is not available
        defaultNS: NAMESPACES.errors,
        resources,
        load: 'currentOnly', // only load the detected language
        ns: [NAMESPACES.definitions, NAMESPACES.errors], // namespaces
        saveMissing: true, // send not translated keys to endpoint
        returnNull: false,
    } as InitOptions);

export default i18nInstance;

In my code, I'm calling the getFixedT function likes so:

const locale = "en";
const t = i18nInstance.getFixedT(locale, NAMESPACES.errors)

t("path.to.definition", { variable: "value" });

I get the following ts error:

No overload matches this call.
  Overload 1 of 2, '(lng: null, ns: Namespace<"en"> | null, keyPrefix?: KeyPrefix<Namespace<"en">>): TFunction<Namespace<"en">, KeyPrefix<Namespace<"en">>, Namespace<...>>', gave the following error.
    Argument of type 'Locale' is not assignable to parameter of type 'null'.
      Type '"de"' is not assignable to type 'null'.
  Overload 2 of 2, '(lng: string | readonly string[], ns?: Namespace<"en"> | null | undefined, keyPrefix?: undefined): TFunction<Namespace<"en">, undefined, Namespace<"en">>', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'Namespace<"en"> | null | undefined'.ts(2769)
  • i18next version: ^22.4.9
  • os: Mac
like image 735
bildungsroman Avatar asked Sep 02 '25 02:09

bildungsroman


1 Answers

I was able to reproduce your issue and found 2 problems, and a solution 🙃

Namespace<"en"> | null | undefined

First, according to https://www.i18next.com/overview/typescript, resources should contain just the namespaces (without wrapping them in language code). For example, you can use your resources.ts, and do:

declare module "i18next" {
    interface CustomTypeOptions {
        // I removed `ns`, as it is not supported in i18n
        returnNull: false;
        resources: typeof resources['en']; // equivalent of typeof { definitions: {...}, errors: {...} }
    }
}

After above change, I got this error:

Argument of type 'string' is not assignable to parameter of type '`Namespace<"definitions" | "errors"> | null | undefined'.ts(2769)

Remaining problem is that TypeScript can not infer the type of your namespace keys (each key was treated as a plain string, instead of a literal value). We can fix that with as const:

// As const
export const NAMESPACES = {
  definitions: "definitions",
  errors: "errors",
} as const;
like image 137
Krzysztof Miemiec Avatar answered Sep 08 '25 09:09

Krzysztof Miemiec