如何优化这种数据类型定义(typescript)

新手上路,请多包涵

我有一个数据类型,大致如下:

interface Graph {
  type: 'circle' | 'rectangle'
  longth?: number
  width?: number
  radius?: number
  area?: number
}

typearea属性必定存在
type === 'circle'的时候,radius属性必定存在,widthlength属性不存在
type === 'rectangle'的时候,widthlength属性必定存在,radius属性不存在

总的来说就是,根据type的变化,这个Graph类型会有不同的属性

需要考虑到的情况:

  1. type可能有10种以上,并且随时都有可能加入新的图形(从而带来新的属性)
  2. 有的属性可能是两三种图形共有,有的可能是所有图形共有(但是新添加的图形可能让这个属性变成部分共有)。
阅读 1.9k
2 个回答

这里需求涉及到分层的多种图形,比如

  • 所有对象都是图形 (Graph)
  • 其中有圆形 (Circle)
  • 也有矩形 (Rectangle)

每种具体的图形有什么属性自己决定,但作为 Graph 来说,只需要知道它的面积 (area)。当然为了便于区分对象,还需要一个 type

那么,我们可以认为,Circle GraphRectangle Graph …… 可以使用继承关系

interface Graph {
    type: string;
    area: number;
}

interface Circle extends Graph {
    type: "circle";
    radius: number;
}

interface Rectangle extends Graph {
    type: "rectangle";
    width: number;
    height: number;
}

这组关系中,Graph 只需要 typearea 两个固有属性。其中 type 要兼容所有子类中的重载,所以需要定义成 string。而 CircleRectangle 会继承 Graph 的属性,同时会具体化 type,并添加一些自己特有的属性

现在要加入正方形怎么办?虽然从常识上来说,正方形矩形,但从类型的角度来说,type 既然已经声明为 rectangle,就不可能具体化square。所以需要引入一个基类型 RectangleBase

interface RectangleBase extends Graph {
    type: "rectangle" | "square";
    width: number;
}

interface Square extends RectangleBase {
    type: "square";
}

interface Rectangle extends RectangleBase {
    type: "rectangle";
    width: number;
    height: number;
}

建议学习一下“面向对象”的相关知识

还有我的课程「TypeScript从入门到实践 【2021 版】」,考虑一下!!


已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

最方便类型推导的做法,对于有些几个图形共有的也可以写在BaseGraph里,在没有该属性的interface里在继承BaseGraph的时候把该属性Omit掉就行

interface BaseGraph {
  type: string
  area?: number
}

interface Cycle extends BaseGraph {
  type: 'circle'
  radius?: number
}

interface Rectange extends BaseGraph {
  type: 'rectangle'
  longth?: number
  width?: number
}

type Graph = Cycle | Rectange