typescript类型保护在react中props的应用
场景: 假如在react的父组件向子组件传递参数有两种类型,而两种参数类型有公共的也有不同的,如何不用可选参数去规范传递参数呢?
如: 现在parent.tsx组件中想要child.tsx子组件,传递男性、女性两种对象,他们有公共属性name,gender,不同的是他们有各自的私有属性:男性有salary,女性有weight。
可选参数的方式
实现方式
在child组件中声明props类型, 限制gender为:male | female
1 2 3 4 5 6 7
| type Props = { name: string gender: 'male' | 'female' salary?: number weight?: number }
|
现在想要在child中展示根据传入的数据分别展示男性和女性的数据
1 2 3 4 5 6 7 8 9 10 11 12 13
| import * as React from 'react' import Child from './child'
export default function Parent() { return ( <div> <Child name="tom" gender="male" salary={1200} weight={50}></Child> <Child name="mary" gender="female" salary={1200} weight={50}></Child> </div> ) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| export default function Child(props: Props) { function InfoItem() { if (props.gender === 'male') { return ( <p> gender: {props.gender}, 工资: {props.salary} </p> ) } else { return ( <p> gender: {props.gender}, 体重: {props.weight} </p> ) } }
return ( <div> <p>child.name: {props.name}</p> <div> <p>InfoItem:</p> <InfoItem /> </div> </div> ) }
|
结果与问题
能够达到正常的效果,但是又好像有点不太友好,因为我想要当gender为male时只能传salary,不能传weight,同样,为female时则只能传weight。
目前可选参数并不能做到限制parent组件中传参和child渲染判断 gender 与 salary weight之间的关系。

使用union类型做类型保护
可以使用联合类型的方式来做类型保护
1 2 3 4 5 6 7 8 9 10 11 12 13
| type Props = { name: string } & (maleProps | femaleProps)
type maleProps = { gender: 'male' salary: number }
type femaleProps = { gender: 'female' weight: number }
|
在联合类型maleProps、femaleProps中限制gender属性值和各自的私有属性.
这样当props.gender为male时,则命中maleProps,实际props就等同于:
1 2 3 4 5
| type Props = { name: string gender: 'male' salary: number }
|
当props.gender为famale时,则命中famaleProps,实际props就等同于:
1 2 3 4 5
| type Props = { name: string gender: 'female' weight: number }
|
实现的效果
此时child中判断就能够根据前置条件判断属性了 parent也会根据之前传入的参数做限制了。


在response响应数据中的应用
在请求数据的时候也可以根据响应的状态来限制响应体中只有数据或错误信息.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type ResponseData<T> = SuccessRes<T> | ErrorRes
type SuccessRes<T> = { status: 'success', data: T, timestamp: Date } type ErrorRes = { status: 'error', message: string, timestamp: Date }
const res1:ResponseData<number> = { status: 'success', data:100, timestamp: new Date() } const res2:ResponseData<number> = { status: 'error', message: 'api error', timestamp: new Date() }
|
如果属性没有对应上status也会报错

ps:
https://stackblitz.com/edit/stackblitz-starters-hyceax?file=src%2FApp.tsx
https://www.youtube.com/watch?v=9i38FPugxB8