Closed
Description
Bug Report - await Promise.all fails to resolve due to optional chaining inside JSX
I am sorry if this doesn't end up being a TypeScript bug, I'm just not able to replicate this without React at the moment. This feels more like a TypeScript issue? So I'll let you guys decide.
🔎 Search Terms
await Promise.all toString JSX ReactNode
🕗 Version & Regression Information
- This is a type checking error
- Broken on 4.9.4, works with version 4.6.2
- I am only able to replicate this with React 17.0.2, not react 18
⏯ Repo Link
Sorry, I have to use a repo for this. It's a bit of a setup to create the conditions for this.
https://github.com/Fish1/bughunter
💻 Code
/src/pages/HomePage.tsx
import { ReactNode } from "react";
import MyList from "../component/MyList";
function HomePage() {
async function myUnusedFunction() {
const getDataFetch1 = Promise.resolve(["hello", "world"])
const getDataFetch2 = Promise.resolve([{ id: 1 }, { id: 2 }])
const [data1, data2] = await Promise.all([
getDataFetch1, getDataFetch2
]);
// *******************************
// TypeScript thinks data2 is a Promise<{ id: number; }[]>
const x = data2.map((data) => {
return data.id.toString();
});
// *******************************
// TypeScript thinks data1 is a Promise<string[]>
const y = data1.map((data) => {
return data.toString();
});
return { x, y };
}
const myNodeArray: ReactNode[] = [
<div>hello</div>,
<div>world</div>,
"hello",
"sup",
]
return (
<div>
<h1>Home Page</h1>
<MyList columnsCurrent={myNodeArray}/>
</div>
);
}
export default HomePage;
/src/component/MyList.tsx
import { ReactNode } from "react";
export interface ListThingProps {
columnsCurrent: ReactNode[],
}
function MyList(props: ListThingProps) {
const { columnsCurrent } = props;
return (
<div>
{
columnsCurrent.map((column, index) => {
/**
* *******************************************************************
* This variable existing will cause Promise.all() to not resolve its promises.
* *******************************************************************
*/
const brokenString = column?.toString();
return (
<div key={index}>
{/* remove {column} here to fix the Promise.all() error */}
{column}
</div>
)
})
}
</div>
);
}
export default MyList;
output of npx tsc
src/pages/HomePage.tsx:14:23 - error TS2339: Property 'map' does not exist on type 'Promise<{ id: number; }[]>'.
14 const x = data2.map((data) => {
~~~
src/pages/HomePage.tsx:14:23
14 const x = data2.map((data) => {
~~~
Did you forget to use 'await'?
src/pages/HomePage.tsx:14:28 - error TS7006: Parameter 'data' implicitly has an 'any' type.
14 const x = data2.map((data) => {
~~~~
src/pages/HomePage.tsx:18:23 - error TS2339: Property 'map' does not exist on type 'Promise<string[]>'.
18 const y = data1.map((data) => {
~~~
src/pages/HomePage.tsx:18:23
18 const y = data1.map((data) => {
~~~
Did you forget to use 'await'?
src/pages/HomePage.tsx:18:28 - error TS7006: Parameter 'data' implicitly has an 'any' type.
18 const y = data1.map((data) => {
~~~~
Found 4 errors in the same file, starting at: src/pages/HomePage.tsx:14
🙁 Actual behavior
await Promise.all doesn't resolve the promises.
🙂 Expected behavior
I expect Promise.all() to resolve it's types correctly regardless of a variable in another file.
Strange Solutions that I have come up with
- Comment out the brokenString variable in /src/component/MyList.tsx
- Uncomment the FixPromiseError() function in src/pages/DummyPage.tsx
- Remove {column} from inside the div in /src/component/MyList.tsx
Here is a link to the TypeScript community discord, and the thread with a lots more testing.
https://discord.com/channels/508357248330760243/1068268321998372964