TS 接口 关于联合类型和交叉类型的使用问题 Array<A | B>

问题描述

我有一个数据结构,需要一个数组对象children里面同时存在RowItem和ColItem两种类型。需要验证该对象属于某种类型时,它的属性是否都有。 比如当children中的对象为RowItem类型时(假设此时RowItem类型有三个属性a,b,c)那么就要验证该对象是否有a,b,c这三个属性

问题出现的环境背景及自己尝试过哪些方法

我的理解,其实我需要的是一个或的关系,当它为具体某一种对象时,再去验证该种对象的类型。
所以我对children试过以下两种结果,但是都不理想。

  1. chilren:Array<rowItem | colItem>
  2. chilren:Array<rowItem> | Array<colItem>

第一种在使用chilren.map(item => item)遍历时,item只能访问rowItem和colItem共有类型
第二种在map时ts就会报错

  1. chilren:Array<rowItem & colItem>

这种交叉类型虽然map时不会报错,就失去了我这样定义接口的意义,因为它无法判断当item为某一个具体类型时,其属性是否完整正确

相关代码

export type RowItem = {
  id: string 
  pid: string
  type: 'row'
  colType: ColType
  rowType: RowType
  formData: string | {
    filed: string
    prop: string
    word: string
  }
}

export type ColItem = {
  id: string 
  pid: string
  type: 'col'
  colType: ColType
  children: Array<RowItem | ColItem>
}

export type ColType = 'and' | 'or'
export type RowType = 'condition' | 'formula'

// compoenent
interface State {
  filterTree: Array<RowItem | ColItem>
}

你期待的结果是什么?

我期望能有一种接口方式,来实现允许children中存在两种不同的类型RowItem和ColItem,当他们为其中任意一个类型(这里有一个问题,及时在map的时候,其实计算机也不知道它具体是哪个类型)时可以根据RowItem和ColItem进行验证。

一种折中方案

将children:any
然后在chilren.map(item => item)的时候,我先手动判断item是具体属于哪个类型,然后再用as指定它属于具体的某种类型。

但是我还没有这样做,是觉得:

  1. 应该有更好地解决方法,或者我理解的有问题
  2. 这个数据结构我会对它进行各种不同层级的增删操作比较复杂,不知道写起来方不方便
阅读 5.2k
1 个回答

其实你已经说了,编译器也无法在编译过程中确定属于哪种类型,所以你的折中方案也差不多是最终方案,你需要手动确认数据类型。

const enum ItemCategory {
    Row = 'row',
    Col = 'col'
}

export interface RowItem {
    id: string
    pid: string
    type: ItemCategory.Row
    colType: ColType
    rowType: RowType
    formData: string | {
        filed: string
        prop: string
        word: string
    }
}
export interface ColItem {
    id: string
    pid: string
    type: ItemCategory.Col
    colType: ColType
    children: Array<RowItem | ColItem>
}

type Item = RowItem | ColItem;

export type ColType = 'and' | 'or'
export type RowType = 'condition' | 'formula'

// compoenent
interface State {
    filterTree: Array<RowItem | ColItem>
}

const i: Item[] = [
    {
        type: ItemCategory.Col,
        id: '',
        pid: '',
        colType: 'and',
        children: []
    }
]

i.map(o => {
    switch (o.type) {
        case ItemCategory.Col: {
            // ...
        };
        case ItemCategory.Row: {
            // ...
        };
    }
})
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题