场景是这样的:
一个活动详情页面,有如下通用参数:id,title,imageUrl,description
于是我定义了一个通用接口:
interface ActivityDetailBase {
id: number
title: string
imageUrl: string
description: string
}
同时,现在有两个活动,A活动、B活动,都有上述那些参数。但也有些区别,A活动详情里面有price,totalLimit;B活动详情有beginTime,endTime。于是我分别定义了两个接口:
interface ADetail extends ActivityDetailBase {
price: number
totalLimit: string
}
interface BDetail extends ActivityDetailBase {
beginTime: number
endTime: number
}
现在进入详情页时在页面路径后拼接参数type=A或type=B,详情页中定义的活动详情对象:
const activityDetail = reactive({
data: <ADetail | BDetail>{}
})
想知道,怎么根据type的值来动态设置activityDetail的类型?
如果type=A,则activityDetail的类型则为 ADetail
如果type=B,则activityDetail的类型则为 BDetail
如果要在页面上显示price,则需要在模板中这样写,感觉比较麻烦
<div>{{ (activityDetail.data as ADetail).price}}</div>
如果想取 beginTime,endTime的值:就得用as语法来断言
function test() {
const { beginTime, endTime } = activityDetail.data as BDetail
// ......
}
通常来说的话是:
然后 TS 会自动推断:
不过这只限于在 TS 中,你这里似乎是需要通过 vue 的 v-if 来实现相关判断,那在模板里还是得类型断言,这么做意义就不大了。
除了 @IanSun 提到的拆成两个组件以外,如果不同类型下页面本身整体变化并不大,只是控制某些活动部分显示或隐藏,你也可以考虑声明类型时都放在一起就好:
模板里该 v-if 判断就继续判断,然后后面正常取值 + 非空断言就可以了,不需要类型断言。
因为其实在后端吧这玩意儿大概率就是同一张数据库表、同一个实体模型,后端本身就是定义在一起的没做区分。