Skip to content

Conversation

@codomposer
Copy link
Contributor

@codomposer codomposer commented Oct 30, 2025

Fixes

Closes #1772

Checklist

  • only relevant code is changed (make a diff before you submit the PR)
  • run tests npm run test
  • tests are included
  • commit message and code follows the Developer's Certification of Origin

Checklist (for documentation change)

  • only relevant documentation part is changed (make a diff before you submit the PR)
  • motivation/reason is provided
  • commit message and code follows the Developer's Certification of Origin

Contribution by Gittensor, learn more at https://gittensor.io/

@coveralls
Copy link

coveralls commented Oct 30, 2025

Coverage Status

coverage: 97.44% (+0.001%) from 97.439%
when pulling d1735d5 on codomposer:fix/trans_type_safe
into 8eeaf96 on i18next:master.

@codomposer
Copy link
Contributor Author

@ahrjarrett @marcalexiei @adrai
can you please check this pull request?

@adrai
Copy link
Member

adrai commented Nov 11, 2025

lgtm but @marcalexiei or some other TS expert should also have a look at this...
btw. @samuelpucat @GorvGoyl maybe you can also have a look at this?

Copy link
Contributor

@marcalexiei marcalexiei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrai copying these four types directly from i18next isn’t ideal, IMHO, as it would increase maintenance overhead:

Keeping these types in sync across both repositories would be necessary to ensure consistent behaviour,
and that might become harder to manage if other plugins need this feature in the future.

Ideally, i18next itself should document that these four types are used externally and need to stay aligned.

That said, if maintaining these types across repos is acceptable to you, feel free to proceed.

Alternatively, a cleaner solution might be to export InterpolationMap directly from i18next and reuse it here.
If you go with this approach, don’t forget to update the semver peerDependencies#i18next version in package.json.

@adrai
Copy link
Member

adrai commented Nov 11, 2025

Alternatively, a cleaner solution might be to export InterpolationMap directly from i18next and reuse it here.
If you go with this approach, don’t forget to update the semver peerDependencies#i18next version in package.json.

@codomposer can you update the PR (rebase with master), to make use of InterpolationMap (i18next v25.6.2 exports it)

@codomposer
Copy link
Contributor Author

Alternatively, a cleaner solution might be to export InterpolationMap directly from i18next and reuse it here.
If you go with this approach, don’t forget to update the semver peerDependencies#i18next version in package.json.

@codomposer can you update the PR (rebase with master), to make use of InterpolationMap (i18next v25.6.2 exports it)

I've updated the PR, can you please check it?

@adrai
Copy link
Member

adrai commented Nov 11, 2025

please update the PR to only include the relevant changes....
btw: the typescript tests are failing

@codomposer
Copy link
Contributor Author

fixed test failures

@adrai
Copy link
Member

adrai commented Nov 11, 2025

@marcalexiei can you please check if it's better like that?

* Distributive version of InterpolationMap that works correctly with union types
* This ensures each key is processed individually rather than creating an intersection
*/
type TransInterpolationMap<Ns extends Namespace, Key, TOpt extends TOptions> = Key extends any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key extends any is always true since all types extend any.
Is this constraint / type necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it as a fix for test failures,
without it, users would need to provide all interpolation variables from all possible keys

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checkout your branch and I'm unable to get any autocomplete information within test files:

Image Image

I'm also getting different result from what is stated in the comments

Image

even calling using tsx syntax:

Image

Am I missing something?

Copy link
Contributor Author

@codomposer codomposer Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the type is exported but doesn't parse {{variable}} syntax from translation strings, and can't provide intellisense.
to enable that, I think I should create a custom type that extracts interpolation variables from translation strings or I will modify the comment, let me know your thoughts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of the PR is to make Trans components type-safe.
Based on this I suppose that at least one of the following behaviours on values prop:

  • (This is mandatory IMHO) Right now values is typed as a top type (any or unknown) this allows any type to be provided which is something that I do not consider safe from a type perspective.
    image

  • (Nice to have) autocomplete on values keys (CustomTypeOptions['resources'] are const strings),
    as per my previous screenshot this is not happening.
    No key is suggested, if this is not feasible the comment on test is misleading and should be changed.

  • (Nice to have) if I pass an invalid values key typescript should report an error... right now any key is accepted.
    Screenshot 2025-11-11 at 13 45 24

If I'm not mistaken this feature is present for tFunction so if additional logic from the core is needed to achieve it should be exported from i18next.

Besides I think you should also add test cases for the selector API created by @ahrjarrett.

@codomposer
Copy link
Contributor Author

@marcalexiei
can you please check the update again?

type ValuesType = TitleProps['values'];

// @ts-expect-error - empty object should not be assignable when appName is required
const invalidValues: ValuesType = {};
Copy link
Contributor

@marcalexiei marcalexiei Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const invalidValues: ValuesType = {};
assertType<ValuesType>({});

You need to add assertType in vitest import

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing this in a real app:

There is an issue with string (import from json) + selector API and context:

import { Trans } from "react-i18next";

export function TranCmp() {
  const someCondition = true;
  return (
    <div>
      <Trans
        ns="ns1"
        i18nKey={($) => $.food}
        context="pizza"
        values={{ test: "a" }}
      />
      <Trans
        ns="ns1"
        i18nKey={($) => $.food}
        context={someCondition ? "pizza" : undefined}
        values={{ test: "a" }}
      />
    </div>
  );
}

with this translation file:

{
  "food": "food",
  "food_pizza": "pizza"
}

You can find the code here: https://github.com/marcalexiei/i18next-playground/tree/main/examples/react-trans-component-type-safe-selector

Image
Type '{ test: string; }' is not assignable to type 'undefined'.
The expected type comes from property 'values' which is declared here on type 'IntrinsicAttributes & TransSelectorProps<SelectorFn<{ prova: string; prova_other: string; job: string; job_details: { title: string; }; food: string; food_pizza: string; }, string, { context: "pizza"; }>, "ns1", undefined, "pizza", { ...; }> & HTMLProps<...>'

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

react-i18next <Trans /> component values are not type safe

4 participants