react-i18next
react-i18next copied to clipboard
This JSX tag's 'children' prop expects a single child of type 'ReactI18NextChild | Iterable<ReactI18NextChild>' when using `allowObjectInHTMLChildren`
🐛 Bug Report
After upgrading to React v18 and Reacti18Next to v11.18, I had an issue with objects not being accepted inside the Trans
component, something similar to this.
The fix for that was to add the allowObjectInHTMLChildren
property, which fix that issue, but it lead to another issue.
Now, when I try to have the result of a t
function along with some other strings inside a p
or span
component, I get the error
This JSX tag's 'children' prop expects a single child of type 'ReactI18NextChild | Iterable<ReactI18NextChild>' when using `allowObjectInHTMLChildren
To Reproduce
Codesandbox - https://codesandbox.io/s/react-i18next-type-issue-uidhq7
Please check the error on src/App.tsx:10
<p>{t("simpleContent")} with extra stuff</p>
Proposed Solution
I tried playing around with the types in the library and it seems like changing node_modules/react-i18next/ts4.1/index.d.ts:108
as follows will fix this.
declare module 'react' {
interface HTMLAttributes<T> {
children?: ReactI18NextChild | ReactI18NextChild[];
}
}
The problem, at least for me, seems to be with Iterable<ReactI18NextChild>
not working as expected for multiple children
Hi @pedrodurek, any update on this? I was planning on using https://github.com/ds300/patch-package to solve this for now, unless a PR is in the works?
We're also having this problem unfortunately. ☹️
same problem also with React 17 and react-i18next (v11.18.3)
This is probably because the type definition is React.ReactNode | Record<string, unknown>
, while i18next type definition has object
in the union type: https://github.com/i18next/i18next/blob/132a02461479c1b14709ff0bce1db484578ccb30/index.d.ts#L687
I think (could be wrong) that Record<string, unknown>
and object are not compatible if you change i18next to React.ReactNode | object
it works.
I also changed from Iterable<ReactI18NextChild>
to ReactI18NextChild[]
I'm having a similar problem with PropTypes.InferProps. If I use PropTypes.node for my children prop, and use {children} in a simple div, I get this error:
Type 'ReactNodeLike' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'. Type '{}' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'.
Never do this in open source libs. If you want to get custom children, use custom (alias) types. Never reassign types of different lib!
Same problem after bumping React to v18
Same
Same issue here
same here
same issue here
same issue if you have something like <span>{props.somePassedInReactNodeOrReactElement}</span>
Type 'ReactNode' is not assignable to type ReactI18NextChild | Iterable<ReactI18NextChild>
.
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.
Same issue here
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.
Same issue
This is a big issue relative to typingm due to redefining children of react module. This is not a good practise, as it breaks other typings.
This JSX tag's 'children' prop expects a single child of type 'ReactI18NextChild | Iterable<ReactI18NextChild>', but multiple children were provided.
but multiple children were provided.
Is that really the solution to just ignore the growing number of Typescript Users? Why has this type been overridden in the first place? Just leave react typings alone, please! Does it really need that override? What is it for?
@rene-stesl idk...but this module is far from ignoring typescript users. Just go through the changelog https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md and check how many releases are just related to work for typescript users.
@pedrodurek puts a lot of his own (free) time into improving the typings and does an awesome job for the community.
Thanks for backing me up @jamuhl, I appreciate it!
@rene-stesl, the types here work perfectly, sometimes it's just hard to please everyone, but I'm doing my best here to address the issues whenever I have free time.
When it comes to complex types like the i18next ones, where we recursively go through all translations to infer the appropriate keys
and return
type, we need to be careful to address some issues due to compilation time concern, so there is a lot of effort on testing and benchmarking it.
@jamuhl, @pedrodurek I know that it is not easy to sacrifice your free time for such a project and only get criticism. This is definitely not my intention.
But IMHO this ticket gets ignored since it was opened on Aug 15. I personally don't think the Types work perfectly in this case because if you just add react-i18next as dependency to an existing project it is possible that the build fails! And I personally think that just adding a dependency to a project shouldn't be able to do that!
If someone can explain why the React Types were overwritten, it might be easier to find a solution.
@rene-stesl
I guess (not a typescript user):
- react team decided to make types stricter not allowing objects inside the react-element children array (as it makes no sense to their use case -> you can't render objects)
in react-i18next we decided long before that objects are a good way to pass in interpolation values and keeping i18next translation syntax <Trans>Some interpolation by passing in an object {{theObject}}</Trans>
. That is absolute valid in javascript.
So the solution is either to extend the types or not using objects inside react-elements.
(Like said - i don't use typescript - so I just believe that this was the reason)
@pedrodurek I'd love to hear your thoughts on this problem since you are clearly a Typescript user. I think most people on this thread use typescript and I would hope that if the real crux of the problem was clarified, then maybe someone might find an elegant solution that makes your life easy.
Ok so I just quickly went over the the said typings. I would love to take a deeper look but I have absolutely no time for this.
As far as I can see the react typing for the DOMAttributes look like this (and it seems like this was even the case with react 16, so no changes there)
interface DOMAttributes<T> {
children?: ReactNode | undefined;
...
The override of react-i18next
type ObjectOrNever = TypeOptions['allowObjectInHTMLChildren'] extends true
? Record<string, unknown>
: never;
type ReactI18NextChild = React.ReactNode | ObjectOrNever;
declare module 'react' {
interface HTMLAttributes<T> {
children?: ReactI18NextChild | Iterable<ReactI18NextChild>;
}
}
I'm absolutely no Typescript expert but the proposed solution by @davehowson is working and would be my suggested quick fix as well. I guess that the problem lies in the use of the Iterable interface, since any Object could be iterable if it implements the interface. So my best bet is that the Typescript interpreter just want's to tell us that our provided Object doesn't implement the Iterable interface and therefore throws this error. With the use of ReactI18NextChild[] however, we tell Typescript that it has to be an Array. So Typescript knows that the Object applies to ReactI18NextChild instead of Iterable<ReactI18NextChild>. But as said I'm really no expert, I'm just guessing 🤣😉😅.
The big question is since react 16 used the same typing for the children, why is this "hack" needed now?
Just a workaround: serve your children inside fragment <></>
.
Hi, did you try to add allowObjectInHTMLChildren: true
and change the declare module 'react-i18next'
by declare module 'i18next'
in react-i18next.d.ts
?
import 'react-i18next'
declare module 'i18next' { // change from react-i18next to i18next
interface CustomTypeOptions {
returnNull: false
allowObjectInHTMLChildren: true // add this solve my issue
}
}
I have react-i18next
v12, typescript
v4.9 and react
v18.2
I think https://github.com/i18next/i18next/issues/1859 is a duplicate of this issue
Same issue here! type '{ lng: ReactNode; }' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'.
Object literal may only specify known properties, and 'lng' does not exist in type 'ReactElement<any, string | JSXElementConstructor
The expected type comes from property 'children' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>'
out of curiosity... check with i18next v22.4.5
Tried it with v22.4.6, same issue:
TS2322: Type 'ReactNode | ((data: DataNode) => ReactNode)' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'. Type '(data: DataNode) => ReactNode' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'.
Even tried to update react-i18next from 11.18.6 to 12.1.1, but then i get a big pile of typescript errors. e.g:
- TS2746: This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided
- TS2322: Type 'ReactI18NextChild | Iterable<ReactI18NextChild>' is not assignable to type 'ReactNode'. Type 'Record<string, unknown>' is not assignable to type 'ReactNode'. Type 'Record<string, unknown>' is missing the following properties from type 'ReactPortal': key, children, type, props