关于TypeScript联合类型报表达式有误的问题
今天在工作时使用TypeScript联合类型导致报了一个“表达式有误”的错,因为这个错误出现的位置是在reduce方法上,一个数组使用reduce居然报错了。
问题描述
课程和考试接口都有一个状态码,他们分别标识这个课程或考试是否完成,现在我需要计算出他们课程和考试的完成进度。由于他们代码逻辑是一样的,不一样的是传入的数组和状态的字段,所以我选择写一个函数对他们进行复用。
代码如下
interface Course{
courseStatus:boolean
}
interface Exam{
examStatus:boolean
}
const getCount = (isCourse: boolean) => {
const feild = isCourse?'courseStatus':'examStatus'
return (list: Course[] | Exam[]) => {
return list.reduce((total,curr) => {
return total+(curr[feild]?1:0)
},0)
}
}
const getCourseCount = getCount(true)
const getExamCount = getCount(false)
复制代码
但是这个时候却出现了一个报错。
这是为啥了,报错显示我的list.reduce的表达式有误。
解决过程
我检查了一下我的list是一个数组,数组肯定是有reduce的呀,为什么会表达式有误,我把上面联合类型去掉一个类型后就没有报错了。知其然还得知其所以然,于是就疯狂翻文档,无果,去摸鱼群问问大佬们。
大佬一眼就看出是联合类型的问题,还纠正了我的写法,应改为
//这块代码是正确写法
interface Course{
courseStatus:boolean
}
interface Exam{
examStatus:boolean
}
const getCount = (isCourse: boolean) => {
const feild = isCourse?'courseStatus':'examStatus'
return (list: (Course | Exam)[]) => {
//return (list: Course[] | Exam[]) => {
return list.reduce((total,curr) => {
return total+(curr[feild]?1:0)
},0)
}
}
复制代码
这是为什么呢?
如果是以”course[] | Exam[]”为参数类型的话,方法会以course[]和Exam[]作为参数类型分别跑一遍函数,但是当course[]作为参数类型的时候没有examStatus这个参数,所以报错了,反之亦然。没理解的直接看下面代码。
interface Course{
courseStatus:boolean
}
interface Exam{
examStatus:boolean
}
//ts语法检查
//以Course[]作为类型检查一遍
const getCount = (isCourse: boolean) => {
const feild = isCourse?'courseStatus':'examStatus'
return (list: Course[]) => {
return list.reduce((total,curr) => {
//检查到这里发现feild的取值是courseStatus和examStatus其中一个。这里如果feild取了examStatus,上面传入的list类型里没有examStatus,所以报错了。
return total+(curr[feild]?1:0)
},0)
}
}
//再以Exam[]作为类型检查一遍
const getCount = (isCourse: boolean) => {
const feild = isCourse?'courseStatus':'examStatus'
return (list: Exam[]) => {
return list.reduce((total,curr) => {
//这个跟上面同理,feild取了courseStatus,上面传入的list类型里没有courseStatus,所以报错了。
return total+(curr[feild]?1:0)
},0)
}
}
复制代码
所以,当接口拥有相同属性的时候也可以不会有以上的报错,稍微改了一下接口的属性名和去掉方法无用的部分,得出:
interface Course{
status:boolean
}
interface Exam{
status:boolean
}
const getCount = (list: Course[] | Exam[]) => {
return list.reduce((total,curr) => {
return total+(curr.status?1:0)
},0)
}
复制代码
这种情况下是不会报错的,因为Course[]和Exam[]中都有status这个字段名。
如果是以”(course | Exam)[]”为参数类型的话,代码检测可以看成是把2个接口合成一个新的接口。
interface Course{
courseStatus:boolean
}
interface Exam{
examStatus:boolean
}
/***
* ts语法检查
* 以(Course|Exam)[]作为类型检查一遍,(Course|Exam)相当于把2个接口相交在一起,形成一个新的接口,即:
* interface newType{
* courseStatus:boolean
* examStatus:boolean
* }
* 所以在新的接口下,同时拥有courseStatus和examStatus属性,就不会报错。
*/
const getCount = (isCourse: boolean) => {
const feild = isCourse?'courseStatus':'examStatus'
return (list: (Course|Exam)[]) => {
return list.reduce((total,curr) => {
return total+(curr[feild]?1:0)
},0)
}
}
复制代码
结语
由于本人经验水平有限,难免会有纰漏,对此欢迎指正。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END