Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Dynamic Namespace Inclusion in TFunction for TypeScript Compatibility #1699

Open
ChingHsun opened this issue Nov 30, 2023 · 4 comments
Assignees

Comments

@ChingHsun
Copy link

🐛 Bug Report

When defining a function with t as a parameter using the TFunction type, it should only include the specific namespaces needed within the function.
However, when attempting to use this function within a component that loads more other namespaces, TypeScript raises an error.

onst getNs3Text = (t: TFunction<["ns3"]>) => {
  return t("ns3:third");
};

const Two = () => {
  const { t } = useTranslation(["ns2", "ns3"]); // loaded two namespace
  return (
    <>
      <div>{t("ns2:second")}</div>
      <div>{getNs3Text(t)}</div> // ts-error 🛑  Type '"ns2"' is not assignable to type '"ns3"'.
    </>
  );
};

To Reproduce

codesandbox

Expected behavior

The function getNs3Text should compile successfully, considering that the function itself only requires the "ns3" namespace. The TypeScript error should not occur when using this function within a component that loads more other namespaces.

Allow for the inclusion of additional namespaces in the TFunction type when defining functions, ensuring compatibility with components that load multiple namespaces.

Your Environment

  • runtime version: react 18.2.0, typescript 5.3.2
  • i18next version: i18next 23.7.7, react-i18next: 13.5.0
  • os: Mac
@adrai
Copy link
Member

adrai commented Dec 1, 2023

If you know how to accomplish this feel free to provide a PR.
Alternatively you can do this:

import { useTranslation } from "react-i18next";
import { getNs3Text } from "../utils/getNs3Text";

const Two = () => {
  const { t: t2 } = useTranslation("ns2");
  const { t: t3 } = useTranslation("ns3");
  return (
    <>
      <div>{t2("second")}</div>
      <div>{getNs3Text(t3)}</div>
    </>
  );
};

export default Two;

https://codesandbox.io/p/sandbox/happy-ishizaka-mngp2k

@balzdur
Copy link

balzdur commented Mar 28, 2024

I look into the code, and the issue seems to be related to $TFunctionBrand here :

/** ************************
 * T function declaration *
 ************************* */
export interface TFunction<Ns extends Namespace = DefaultNamespace, KPrefix = undefined> {
  $TFunctionBrand: $IsResourcesDefined extends true ? `${$FirstNamespace<Ns>}` : never;
  <
    const Key extends ParseKeys<Ns, TOpt, KPrefix> | TemplateStringsArray,
    const TOpt extends TOptions,
    Ret extends TFunctionReturn<Ns, AppendKeyPrefix<Key, KPrefix>, TOpt>,
    const ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,
  >(
    ...args:
      | [key: Key | Key[], options?: ActualOptions]
      | [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]
      | [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]
  ): TFunctionReturnOptionalDetails<Ret, TOpt>;
}

What is the purpose of $TFunctionBrand ? (if you remove it, the TS error disapear)

@adrai
Copy link
Member

adrai commented Mar 28, 2024

//cc @jtbandes

@jtbandes
Copy link

What is the purpose of $TFunctionBrand ?

See i18next/i18next#1994

Also see prior discussion on this useTranslation(["ns2", "ns3"]) syntax here: i18next/i18next#1994 (comment) /cc @esetnik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants