4

Iam trying to configure react-i18next 11.8.2 in my React Native app with typescript 4.1.2:

i18n.use(initReactI18next).init({
  resources: {
    en,
    es,
  },
  lng: 'es',
  fallbackLng: 'es',
  interpolation: {
    escapeValue: false,
  },
});

with two resources files (en, es).

But i am getting an typescript error with the TFunction interface using the useTranslation hook:

const {t, i18n} = useTranslation(['SelectLanguage']);]

<StyledLabel>{t('SelectLanguage:title')}</StyledLabel>

The error:

No overload matches this call.
  Overload 1 of 2, '(props: Pick<Pick<TextProps & RefAttributes<Text>, "key" | "ref" | "style" | "onLayout" | "testID" | "nativeID" | "accessible" | "accessibilityActions" | ... 35 more ... | "dataDetectorType"> & Partial<...>, "key" | ... 42 more ... | "dataDetectorType"> & { ...; } & { ...; } & { ...; }): ReactElement<...>', gave the following error.
    Type 'TFunctionResult' is not assignable to type 'string | number | TextElement | ChildElement[] | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | ... 20 more ... | undefined'.
      Type 'null' is not assignable to type 'string | number | TextElement | ChildElement[] | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | ... 20 more ... | undefined'.
  Overload 2 of 2, '(props: StyledComponentPropsWithAs<typeof Text, any, {}, never>): ReactElement<StyledComponentPropsWithAs<typeof Text, any, {}, never>, string | ... 1 more ... | (new (props: any) => Component<...>)>', gave the following error.
    Type 'TFunctionResult' is not assignable to type 'string | number | TextElement | ChildElement[] | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | ... 20 more ... | undefined'.
      Type 'null' is not assignable to type 'string | number | TextElement | ChildElement[] | (string & {}) | (string & ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)>) | ... 20 more ... | undefined'.ts(2769)
text.component.d.ts(15, 5): The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & Pick<Pick<TextProps & RefAttributes<Text>, "key" | "ref" | "style" | "onLayout" | "testID" | ... 38 more ... | "dataDetectorType"> & Partial<...>, "key" | ... 42 more ... | "dataDetectorType"> & { ...; } & { ...; } & { ...; }'
text.component.d.ts(15, 5): The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & Pick<Pick<TextProps & RefAttributes<Text>, "key" | "ref" | "style" | "onLayout" | "testID" | ... 38 more ... | "dataDetectorType"> & Partial<...>, "key" | ... 42 more ... | "dataDetectorType"> & { ...; } & { ...; } & { ...; }'

I can solve this error by parsing the result of the i18n translation like this:

<StyledLabel>{t<string>('SelectLanguage:title')}</StyledLabel>

Do you have any idea of why this is happening? i think it could be the StyledLabel props, it is just an styled component of a @ui-kitten/components Text

import styled from 'styled-components/native';
import {Text} from '@ui-kitten/components';

export const StyledLabel = styled(Text)`
  margin-bottom: 5px;
`;

the text.component of UI Kitten:

export declare class Text extends React.Component<TextProps> {
    render(): React.ReactElement<RNTextProps>;
}
export {};

5 Answers 5

11

In the error message, you can find the problem.

Type 'TFunctionResult' is not assignable to type 'string | number | TextElement | ChildElement[] | (string & {}) | (string & ReactElement<any, string

TFunctionResult accept only string

Solution: You need to always send a string and refer it as string

<StyledLabel>{t<string>('SelectLanguage:title')}</StyledLabel>

Second solution

<StyledLabel>{`${t('SelectLanguage:title')}`}</StyledLabel>
Sign up to request clarification or add additional context in comments.

2 Comments

This isn't about what the function accepts. It's that TFunctionResult will return a string, but it's improperly typed to not be a sub-type of string.
The second solution works for me
1

Create react-i18next.d.ts

import "react-i18next";

import type * as translations from "locales";

declare module "react-i18next" {
  type DefaultResources = typeof translations;
  interface Resources extends DefaultResources {}
}

declare module "react-i18next" {
  type Namespace = keyof typeof translations;
  type Keys<N extends Namespace> = keyof typeof translations[N];

  interface TFunction<
    TResult extends TFunctionResult = string,
    TKeys extends TFunctionKeys = string,
    TInterpolationMap extends object = StringMap
  > {
    // basic usage
    (key: TKeys | TKeys[], options?: TOptions<TInterpolationMap> | string): TResult;
    // overloaded usage
    (key: TKeys | TKeys[], defaultValue?: string, options?: TOptions<TInterpolationMap> | string): TResult;
  }

  type UseTranslationResult<N> = {
    t: TFunction<string, Keys<N>>;
    i18n: i18n;
    ready: boolean;
  };
  export function useTranslation<N extends Namespace>(ns: N, options?: UseTranslationOptions): UseTranslationResult<N>;
}

Comments

1

In my case I was using a ^18 version of the types of React. If your are using React 17, use the correct version:

    "@types/react": "17.0.19",
    "@types/react-dom": "17.0.9",

Comments

0

One other solution is to use withTranslation

import React from "react";
import { Link, Redirect } from "react-router-dom";
import "./Screen.css";
import ImageHolder from "../../../../assets/imageholder.png";
import { withTranslation } from "react-i18next";

export interface Screen3Props {
  t: any;
}

const Screen3: React.FunctionComponent<Screen3Props> = ({ t }: Screen3Props) => {
  const [redirect, setRedirect] = React.useState(false);
  return (
    <div className="ms-welcome initPage">
      <p className="h1">{t("SEARCH_PRIMARY_TEXT")}</p>
      <p className="h2">{t("SEARCH_SECONDARY_TEXT")}</p>
    </div>
  );
};

export default withTranslation()(Screen3);

 

Comments

0

t('SelectLanguage:title').toString() fixed the issue for me

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.