typescript类型保护在react中props的应用

typescript类型保护在react中props的应用

场景: 假如在react的父组件向子组件传递参数有两种类型,而两种参数类型有公共的也有不同的,如何不用可选参数去规范传递参数呢?

如: 现在parent.tsx组件中想要child.tsx子组件,传递男性、女性两种对象,他们有公共属性name,gender,不同的是他们有各自的私有属性:男性有salary,女性有weight

可选参数的方式

实现方式

child组件中声明props类型, 限制gender为:male | female

1
2
3
4
5
6
7
// child.tsx
type Props = {
name: string
gender: 'male' | 'female'
salary?: number // male 私有
weight?: number // female 私有
}

现在想要在child中展示根据传入的数据分别展示男性和女性的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
// parent.tsx
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
// child.tsx
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>
)
}

结果与问题

能够达到正常的效果,但是又好像有点不太友好,因为我想要当gendermale时只能传salary,不能传weight,同样,为female时则只能传weight

目前可选参数并不能做到限制parent组件中传参和child渲染判断 gendersalary weight之间的关系。

pCbvZGT.png

使用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
}

在联合类型malePropsfemaleProps中限制gender属性值和各自的私有属性.
这样当props.gendermale时,则命中maleProps,实际props就等同于:

1
2
3
4
5
type Props = {
name: string
gender: 'male'
salary: number
}

props.genderfamale时,则命中famaleProps,实际props就等同于:

1
2
3
4
5
type Props = {
name: string
gender: 'female'
weight: number
}

实现的效果

此时child中判断就能够根据前置条件判断属性了 parent也会根据之前传入的参数做限制了。

pCbvWLj.png

pCbxilD.png

在response响应数据中的应用

在请求数据的时候也可以根据响应的状态来限制响应体中只有数据或错误信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* eslint-disable @typescript-eslint/no-unused-vars */
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也会报错

pCbxW9K.png

ps:

https://stackblitz.com/edit/stackblitz-starters-hyceax?file=src%2FApp.tsx

https://www.youtube.com/watch?v=9i38FPugxB8


typescript类型保护在react中props的应用
https://avatar0813.github.io/2023/07/22/typescript/typescript类型保护在react中props的应用/
作者
avatar
发布于
2023年7月22日
许可协议