Take a simple react component
interface MyProps {
color: string
name?: string
height?: number
isBoy?: boolean
// only add the following if isBoy is true
actionHero: string
nickname: string
}
function MyComponent(props: MyProps){
...
}
As you can see, the goal is that actionHero
and nickName
are required if isBoy
is set to true. Otherwise, they aren't used.
I assume this is done via function overloading in typescript but how do you do it in react?
CodePudding user response:
You don't need to overload your component in this case. COnsider this example:
import React from 'react'
type Boy = {
color: string
name?: string
height?: number
isBoy: false
}
type ExtendedBoy = Omit<Boy, 'isBoy'> & {
actionHero: string
nickname: string
isBoy: true;
}
type Props = Boy | ExtendedBoy;
function MyComponent(props: Props) {
if (props.isBoy) {
props.nickname // stirng
} else {
props.isBoy // false
}
return <div></div>
}
const withBoy = <MyComponent isBoy color="red" actionHero={'batman'} nickname={'qwert'} /> // ok
const withoutBoy = <MyComponent isBoy={false} color="red" /> // ok
I have used discriminated unions instead function overloading.
BUT, nobody can't stop you if you still want to overload your component:
import React, { FC } from 'react'
type Boy = {
color: string
name?: string
height?: number
isBoy: false
}
type ExtendedBoy = Omit<Boy, 'isBoy'> & {
actionHero: string
nickname: string
isBoy: true;
}
const MyComponent: FC<Boy> & FC<ExtendedBoy> = (props) => {
if (props.isBoy) {
props.nickname // stirng
} else {
props.isBoy // false
}
return <div></div>
}
const withBoy = <MyComponent isBoy color="red" actionHero={'batman'} nickname={'qwert'} /> // ok
const withoutBoy = <MyComponent isBoy={false} color="red" /> // ok
Please be aware that intersection of functions produces function overloading FC<Boy> & FC<ExtendedBoy>
If you are interested in typescript validation in react components, see my article and my blog here and here
CodePudding user response:
It's possible since types have no conditional logic and can't depend on each other with but two mapped types instead. One for the optional properties, and one for the required ones.
interface MyProps {
color: string
name?: string
height?: number
isBoy?: false | null
}
interface MyProperRequired extends MyProps {
isBoy: true
// only add the following if isBoy is true
actionHero: string
nickname: string
}
function MyComponent(props: MyProps | MyProperRequired) {
}
MyComponent({ color: "red", height: 1, name: "hi", isBoy: true })