@types/react
package and had problems.Definitions by:
in index.d.ts
) so they can respond.With current typings it is not possible to create a stateless component which returns a string, number, boolean... (new in React 16)
import React from 'react'
const TestString = () => {
return 'Test String Component'
}
const Component = () => (
<div>
<TestString/>
</div>
)
Error I get:
JSX element type 'string' is not a constructor function for JSX elements.
The first problem is that currently in the typings a stateless component cannot return anything else besides an instance of a React.Element
. This should be changed to (I think, I've based it upon the changes on the render
method, see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L422)
interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | Array<ReactElement<any>> | string | number | null;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
Second problem is that behind the scenes the compiler will convert the jsx to `React.createElement('Test String Component', null)``
I get a compiler error that is saying that this is not a valid value. Seems that it has to be one of the values specified in following list: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L3465.
Any thoughts on how this can be fixed?
@DovydasNavickas @sandersn @tkrotoff @andy-ms @ddwwcruz @apexskier @devrelm @RyanCavanaugh @richseviora @onigoetz @minestarks @yuit @sboehler @plantain-00 @p-jackson @miracle2k @voxmatt @morcerf @janechu @gaspard @vbfox @ericanderson @dyst5422 @rapilabs @cynecx @newyankeecodeshop
We could probably define stateless and class based components as returning ReactNode
now. I haven't migrated to v16 yes, so that would need testing.
Looks like there's already a PR open. https://github.com/DefinitelyTyped/DefinitelyTyped/pull/20097
Is this being worked on atm?
I tried changing it but it breaks the JSX parser if the return type is string
boolean
or undefined
.
There is a TypeScript PR in progress about it : https://github.com/Microsoft/TypeScript/pull/20239 (Well its about arrays but it's generally how TS should know what is allowed in a JSX component)
Cool, thanks for the update!
What's the latest on this? I see the TS PR mentioned above (https://github.com/Microsoft/TypeScript/pull/20239) is now closed/locked. I ran into the same thing today, new to typescript + react, and wondering why my components can't return strings suddenly...
A workaround is to return a fragment.
return <>0</>
Any news on this issue?
Hello, any update or hints on this please :) ?
This is essentially a duplicate of #18912. Once Microsoft/TypeScript#21699 is resolved we should be able to use ReactNode
as a valid return type for function components which includes string
and boolean
.
To generalize the issue, why should it even assume what's legit for React? With the @jsx
/ @jsxFrag
Babel pragmas, an approach like this JSX can work with whatever functions. So it's not even that only strings should be admitted; any return value can be legit, constrained only by the specific use. React is important but it's just a specific rendering library.
This has been open for nearly a couple years now, is there any solution?
About the suggested return a fragment <>StringValue goes here> - I guess I am having trouble understanding how I get the string value, or any other type of value that is not a React.Element really to use in my code - for example if I have a function named Howdy returning <>"hello"> and inside of componentDidMount I have
const whatSays =
how would I get the string value out of the fragment. I'm not seeing a way, it feels like any way to get around this is an extremely ugly hack and considering that the Hooks api is often used with returning just strings or other non React Element values - for example https://github.com/pankod/react-hooks-screen-type/blob/master/src/index.js
it seems to me that this bug really makes the Hooks api unusable, and as such makes Typescript a poor fit for React.
This has been open for nearly a couple years now, is there any solution?
@bryanrasmussen See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20544#issuecomment-459665668 for the last update.
This issue is making us write a-typical React code to work around limitations imposed by TypeScript. The only way to squash these errors in a TypeScript way is to introduce additional DOM elements and/or React.Fragments these add overhead (generate garbage) and they aren't needed.
This isn't always a problem by it crops up every now and is triggered when you return valid things from React components that aren't exactly JSX.Element, for example, an array.
I'd be happy with a sensible type annotation to help things along but I have to squash these with imperfect things like additional layers and/or any
. Not good.
Wrapping with an unnecessary React.Fragment
has a (insignificant) cost at runtime.
Could this be another work around with no runtime penalty ?
import React, { ReactElement } from 'react'
const TestString = () => {
return ('Test String Component' as unknown) as ReactElement
}
const Component = () => (
<div>
<TestString />
</div>
)
export default Component
Wrapping with an unnecessary
React.Fragment
has a (insignificant) cost at runtime.
It's a compromise. Still, would like to see better typing for this. Also, not insignificant, depends on context. A few fragments don't hurt, a lot of them will.
Wrapping with an unnecessary
React.Fragment
has a (insignificant) cost at runtime.Could this be another work around with no runtime penalty ?
import React, { ReactElement } from 'react' const TestString = () => { return ('Test String Component' as unknown) as ReactElement } const Component = () => ( <div> <TestString /> </div> ) export default Component
Yeah, but then I also lose the type checking for the function. I mean I can also remove TS from my project without any runtime penalty but then I have no type checking. So your workaround is surely working but just breaks the purpose of TS. Casting to "what you expect" is like saying "Okay, then lets throw out the breaks. Who needs this anyhow?". When you wrap it in a fragment, you get correct type checking!
So, any news on fix?
Most helpful comment
Any news on this issue?