react-i18next: Cannot pass objects to `` with React 18 type definitions
🐛 Bug Report
With version 18 of @types/react
, Typescript complains when passing objects to the Trans
component.
It previously worked because ReactNode
had a | {}
in its definition, allowing arbitrary objects to be passed. That has been removed (for a good reason) in version 18 of the type definitions. See this PR for more information.
To Reproduce
From this example:
<Trans i18nKey="userMessagesUnread" count={count}>
Hello <strong title={t('nameTitle')}>{{name}}</strong>, you have {{count}} unread message. <Link to="/msgs">Go to messages</Link>.
</Trans>
This fails type checking: TS2322: Type '{ name: void; }' is not assignable to type 'ReactNode'.
Expected behavior
Type checking works, i.e. the TS compiler does not complain.
I would think that {}
(or something like Record<string, unknown>
) should be explicitly added to the children
type of Trans
.
Your Environment
- react version: 18.0.0
- i18next version: 11.16.5
- TS version: 4.6.3
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 21
- Comments: 35 (15 by maintainers)
Commits related to this issue
- Update to `@types/react[-dom]` 18 This came with a few breaking changes. See this for the full explanation: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210 The most impactful for us is... — committed to LukasKalbertodt/tobira by LukasKalbertodt 2 years ago
- タグで囲う順番がまるっきりちがくても大丈夫そう App.tsx:28のエラーは↓をちゃんと読まないといけないけど読んでない。動いてはいる。 https://github.com/i18next/react-i18next/issues/1483 — committed to okudayuuki/react-i18n-sample by okudayuuki 2 years ago
- Work around objects-in-children nonsense See https://github.com/i18next/react-i18next/issues/1483#issuecomment-1268455602 — committed to neinteractiveliterature/intercode by nbudin a year ago
This is still a problem. Please don’t close. (I’m sorry but I can’t think of a single reason why stalebot would be useful…)
Came across this issue as well, here is how I resolved it:
With the translation using the same <1></1> and <3></3>.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
For anyone stumbling across this in the future and needs to figure out how to use the
allowObjectInHTMLChildren
option, you just have to create a type declaration file likesrc/types/react-i18next.d.ts
and then add the following to itIn case it helps anyone else: Using
allowObjectInHTMLChildren
felt fairly drastic (since it changes the allowed prop types of all React components, whether or not they’re part of<Trans>
), and it isn’t perfect (#1543), so I’ve started using typecasts instead:I use a type alias to make this more self-documenting:
(This relies on new work in i18next-parser; see https://github.com/i18next/i18next-parser/issues/603.)
This issue still exists even with
12.2.0
, I’m hoping there will be a fix for this. Making use ofany
is not the workaround I want to go forUsing the suggested .d.ts mod from @dave-multiplier breaks all my other JSX tags with errors like:
The above error is thrown for elements like:
Wrapping
{t('Phone Number')}
inside aspan
tag fixes the problem.For anyone landing here today, this worked fine for me:
where the key is automatically detected as
'You will be signed out in <0>{{ minutesToLogout }}m {{ secondsToLogout }}s</0>'
v11.16.8 offers allowObjectInHTMLChildren option
It’s not a runtime issue…as (not like typescript) javascript is just code 😉…react’s JSX is nothing but a stack of function calls…the JSX element’s children is just an array of objects. So we take that
{{notAllowedObjectInChildren}}
and make what we need with it -> parse it to interpolation values.That way we can use i18next JSON interpolation syntax inside JSX elements…it’s somewhat clever but has its drawbacks with over-restrictive typescript…if it’s good or bad thing might depend on the user.
If typescript users prefer not extending this…the other option is to not allow using Trans in that way -> but use it like for ICU syntax https://react.i18next.com/misc/using-with-icu-format#using-the-trans-component
Upgraded to
v13.0.1
(other i18next pkgs were upgraded as well) and the error was gone.The solution is:
This is not yet fixed. The code in the top level comment now (11.16.7) results in:
The linked PR allowed passing one object as children, but not a list of different objects mixed with strings or nodes. All of these use cases were “supported” via
{}
, which, as far as I know, accepts a whole lot of types. That’s why using{}
is generally discouraged.For the first error, I think this should work:
However, this doesn’t fix the second error. And I’m not sure we can fix it? Here it’s about the
children
ofstrong
, which is defined in React itself.Doesnt work man, error is still there
I personally don’t use objects in HTML tags in my code, so I can’t really say anything about it. But it sounds like such a toggle might be the best way forward. 👍
Sorry for the delay guys! We can change the
TransProps
to also accept array ofobject
andReactNode
, but that doesn’t solve the problem entirely, HTML element children are no longer accepting objects, which means this will not work:So
strong
element doesn’t “accept” objects anymore.That’s not something that we can’t control in “theory”… We can always use type augmentation to change the
HTMLAttributes
children prop to also accept objects. The only problem is that all HTML elements will start accepting objects again, not only the HTML elements wrapped withinTrans
component.Anyway, I created a draft PR https://github.com/i18next/react-i18next/pull/1492 that solves it. If you accept the condition above, we can merge it. I want you to hear your thoughts first!
need @pedrodurek’s feedback here 🙏