I have the following code:
import * as React from 'react'
type ComponentConfig = [true, {name: string}] | [false, null]
const useComponent = (check: boolean): ComponentConfig => {
if (check) {
return [true, {name: 'Some Name'}]
}
return [false, null]
}
const Component = (props: {name: string}) => {
return <div>Hello {props.name}</div>
}
const Parent = () => {
const [shouldRender, props] = useComponent(true);
return (
<>
<div>Some Heading</div>
{shouldRender && <Component {...props} />}
</>
)
}
As you can see, there is a Parent and Child component, however it should be rendered conditionally based on some logic, here represented as "check" argument.
The utility method returns tuple of boolean and props. More specifically, it returns set of props for true case but returns null for false case.
My initial expectation was that Typescript would be able to understand these pathways.
But I get the following error:
Type '{ name?: string | undefined; }' is not assignable to type '{ name: string; }'.
Types of property 'name' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
How can I resolve this error? The above snippet is also reproducible in this Playground Link
>Solution :
Until Typescript 4.6 (yet to be released at the time of writing) the compiler can’t understand that shouldRender and props are related in any way.
If you wait for 4.6, your code should work AS IS. And you can see this in the TS playground if you use the nightly version: Playground Link
Until 4.6 you can use the tuple directly, without destructuring, TS understands the relation between tuple elements:
const Parent = () => {
const shouldRenderAndProps = useComponent(true);
return (
<>
<div>Some Heading</div>
{shouldRenderAndProps[0] && <Component {...shouldRenderAndProps[1]} />}
</>
)
}