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

@types/react does not allow returning ReactPortal from render #20942

Closed
Jessidhia opened this issue Oct 24, 2017 · 15 comments · Fixed by #65135
Closed

@types/react does not allow returning ReactPortal from render #20942

Jessidhia opened this issue Oct 24, 2017 · 15 comments · Fixed by #65135

Comments

@Jessidhia
Copy link
Member

Jessidhia commented Oct 24, 2017

A ReactPortal is not accepted as a valid ReactElement as it does not have a type or props key. However, React itself does accept ReactPortals as a valid return value.

This might be a bit tricky to fix as simply changing StatelessComponent/ComponentClass to return ReactElement|ReactPortal will probably break many things.

This problem will also probably repeat itself with future React.Fragment.

interface PortalProps {
  children: React.ReactNode
  target: Element
}
// type error: ReactPortal not assignable to ReactElement
const Portal: React.SFC<PortalProps> = ({ children, target }: PortalProps) => ReactDOM.createPortal(children, target)
const Portal2 = ({ children, target }: PortalProps) => ReactDOM.createPortal(children, target)
// type error: Portal2 is not a constructor for JSX elements
const test = <Portal2 target={document.body}>test</Portal2>
@charlieman
Copy link

I wonder if this is related, I was just following the tutorial here: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html

And webpack gave me the error "Module has no exported member 'ReactPortal'". Do I need to use a specific version of react or @ types/react?

$ webpack

[at-loader] Using typescript@2.6.1 from typescript and "tsconfig.json" from /home/user/ts-react-example/tsconfig.json.


[at-loader] Checking started in a separate process...

[at-loader] Checking finished with 1 errors
Hash: 4e0027c7639f8f63e2fc
Version: webpack 3.8.1
Time: 2009ms
        Asset     Size  Chunks             Chunk Names
    bundle.js  3.38 kB       0  [emitted]  main
bundle.js.map  3.76 kB       0  [emitted]  main
   [1] ./src/index.tsx 332 bytes {0} [built]
    + 3 hidden modules

ERROR in [at-loader] ./node_modules/@types/react-dom/index.d.ts:16:43 
    TS2305: Module '"/home/user/ts-react-example/node_modules/@types/react/index"' has no exported member 'ReactPortal'.
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

@charlieman
Copy link

charlieman commented Nov 7, 2017

I got it working!

First I noticed the version of @types/react didn't match that of react so I changed it to the same as react (16.0.0).
Then looking at the yarn.lock file, I saw there was two versions of @types/react installed, 15.6.6 and 16.0.0. I ran the command yarn check which gave me this message: warning "@types/react-dom#@types/react@*" could be deduped from "16.0.20" to "@types/react@16.0.20"

So I ran yarn install --flatwhich gave me a version to choose from for @types/react (and several other packages which now give me warnings for incompatible versions). After that running webpack finally worked.

Edit:
I started from scratch, adding the section resolutions to my package.json which gave me the right @types/react version without the other warnings:

  "resolutions": {
    "@types/react": "16.0.20"
  }

@kajmagnus
Copy link

Thanks @charlieman, adding resolutions: ... solved the same problem for me too (I added v. 16.0.25). I have no idea why Yarn insisted on keeping the 15.x version — nothing seems to depend on that old version.

@rosskevin
Copy link
Contributor

rosskevin commented Dec 8, 2017

I am seeing this with

    "@types/react": "^16.0.28",
    "@types/react-dom": "^16.0.3",

So I don't have anything down in 15.x. and have no idea why this is happening.

I did rm -rf node_modules && yarn but no change.

@rosskevin
Copy link
Contributor

rosskevin commented Dec 8, 2017

Ok, so I seem to have figured something out. When I used ncu it updated existing ^16.0.27 to ^16.0.28, and I yarn installed. This somehow put the project in a bad state.

As mentioned above, rm -rf node_modules && yarn didn't solve the problem, but rm -rf node_modules yarn.lock && yarn did solve the problem. Evidently forcing yarn to do a from-scratch dependency resolution had an an effect on the results.

Here is a diff if it could be helpful of the working (new) vs failing yarn.lock: https://gist.github.com/rosskevin/9966b40017a82404147c96327543a40b

@Cryrivers
Copy link

just found out the topic was totally off. @Kovensky i met the same problem, i think the only solution is to update the type definition file. making ReactPortal extend from ReactElement or something like that.

@Cryrivers
Copy link

interface ReactPortal extends ReactElement<any> {
    key: Key | null;
    children: ReactNode;
}

this works for me.

@ccorcos
Copy link

ccorcos commented Mar 14, 2018

I'm still unable to fix this. The problem appears to be that @types/react-dom installs an older version of @types/react as you can see from the error trace:

node_modules/@types/react-dom/node_modules/@types/react/index.d.ts(3566,13): error TS2717: Subsequent property declarations must have the same type.  Property 'a' must be of type 'DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>', but here has type 'DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>'.

Here's what I've got going in my package.json:

	"devDependencies": {
		"@types/react": "16.0.40",
		"@types/react-dom": "16.0.3",
	},
	"resolutions": {
		"@types/react": "16.0.34",
		"@types/react-dom": "16.0.3"
	},

And here's what in my yarn.lock:


"@types/react-dom@16.0.3":
  version "16.0.3"
  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.3.tgz#8accad7eabdab4cca3e1a56f5ccb57de2da0ff64"
  dependencies:
    "@types/node" "*"
    "@types/react" "*"

"@types/react@*", "@types/react@16.0.34":
  version "16.0.34"
  resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.34.tgz#7a8f795afd8a404a9c4af9539b24c75d3996914e"

"@types/react@16.0.40":
  version "16.0.40"
  resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.40.tgz#caabc2296886f40b67f6fc80f0f3464476461df9"

@ccorcos
Copy link

ccorcos commented Mar 14, 2018

Lol, my resolution differed from the dependency version.

Also note for others, you can pin version in subpackages (using resolutions)[https://yarnpkg.com/lang/en/docs/selective-version-resolutions/]

"@types/react-dom/@types/react": "16.0.40"

@lifeiscontent
Copy link
Contributor

I'm trying to use a React.SFC and using a react portal inside complains saying it doesn't have a render function. Anyone know of a fix here?

@netzwerg
Copy link
Contributor

@lifeiscontent I ran into the same problem. Don't know how to fix it, but I managed to work around it by not using JSX.

So instead of this:

<MyComponentWhichUsesAPortal xy={xy}/>

you can use your component like this:

MyComponentWhichUsesAPortal({xy})

@jariz
Copy link

jariz commented May 31, 2018

@lifeiscontent I 'fixed' it by wrapping a <Fragment> around the ReactDOM.createPortal call.
Still really weird SFC does not accept it in the first place. (using the latest versions of all typings)

@SeanRoberts
Copy link

This seems to be fixed with @types/react-dom@16.8.0

@joshuaellis
Copy link
Contributor

joshuaellis commented Jan 13, 2021

At react-three-fiber we've implemented a createPortal function which is identical to ReactDOM.createPortal but it current throws the following error:

Its return type '{ $$typeof: number | symbol; key: string | null; children: any; containerInfo: any; implementation: any; }' is not a valid JSX element.

I've noticed in @types/react theres an exported type ReactPortal but that type doesn't seem to really work either, maybe React.ReactPortal isn't correctly typed by somehow passes? Here's the implementation of react-three-fiber.createPortal:

function createPortal(children: React.ReactNode, containerInfo: any, implementation?: any, key: any = null) {
  if (!containerInfo.__objects) containerInfo.__objects = []
  return {
    $$typeof: REACT_PORTAL_TYPE,
    key: key == null ? null : '' + key,
    children,
    containerInfo,
    implementation,
  }
}

Wrapping the call in a fragment does work, but it's not ideal because we have to ask the user to impliment that...

@orta
Copy link
Collaborator

orta commented Aug 3, 2021

Hi thread, we're moving DefinitelyTyped to use GitHub Discussions for conversations the @types modules in DefinitelyTyped.

To help with the transition, we're closing all issues which haven't had activity in the last 6 months, which includes this issue. If you think closing this issue is a mistake, please pop into the TypeScript Community Discord and mention the issue in the definitely-typed channel.

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

Successfully merging a pull request may close this issue.