扩展多个接口或在Typescript中创建新类(多态)

时间:2019-11-18 16:17:47

标签: typescript class interface polymorphism

我开始在打字稿中对API客户端进行建模,并寻求有关如何正确建模数据的澄清。 API的数据模型都共享一组公共属性(一个抽象),然后每个对象都有更具体的类型。每个对象还将共享一个通用的元数据集($ meta),但每个对象的某些值将有所不同。例如:

type Shapes = "Parallelogram" | "Triangle"
type QuadShapes = "Square" | "Trapezoid" | "Rectangle" | "Rhombus" | "Parallelogram"
type ParallelogramShapes = "Square" | "Rectangle" | "Rhombus" | "Parallelogram"
type TriangleShapes = "Isosceles" | "Scalene" | "Equilateral"


interface Meta {
    id: number
    number_of_sides: number,
    type: Shapes,
    is_quadrilateral: Boolean,
    is_parallelogram: Boolean,
}

interface IShape {
    $meta: Meta
}

interface IQuadrilateral extends IShape {
    $meta.number_of_sides: number
}

interface IParallelogram extends IQuadrilateral {
    $meta.number_of_parallel_sides: number
    $meta.type: ParallelogramShapes
}

interface ITriangle extends IShape {
    $meta.is_parallelogram: Boolean
    $meta.type: TriangleShapes
}

// ISquare should look like: 
//  {    
//      $meta: {
//          id: 1,
//          type: "Parallelogram",
//          parallelogram_type: "Square"
//          is_parallelogram: true,
//          is_quadrilateral: true,
//          number_of_sides: 4,
//          number_of_parallel_sides: 2
//      },
//      name: "Some Square"
//      color: "Blue"
//  }

interface ISquare extends IParallelogram {
    // How do i define the $meta node?
    $meta: 
    name: string,
    color: string
}

class Square implements ISquare {
    $meta: ?
    name: string,
    color: string

    constructor(meta: any, name: string, color: string) {
        this.$meta: meta
        this.name: name.
        this.color: color
    }
}

我不确定是否丢失了某些内容,但是我遇到的最大问题是如何将$meta参数建模到接口中。如何以一致的,非冗余的方式设置$meta.type$meta.is_parallelogram

1 个答案:

答案 0 :(得分:1)

我倾向于重构,以便您的Meta类型形成它们自己的接口层次结构,并且将IShape设为其支持的Meta类型的generic。 / p>

首先,我将重写您的类型。请注意,为了保持一致性,我认为您希望ShapesTriangleShapes | QuadShapes,因为子类型化要求Square实现IShape时,type属性才能分配给{{ 1}}的{​​{1}}属性。但是IShape无法分配给type,因为它们是string literal类型,并且仅引用特定的字符串:

"Square"

现在我们谈论"Parallelogram" | "Triangle"阶层。我认为,这涉及最少的冗余,因为您只需指定比其超类型的属性新的或更窄的属性即可:

type Shapes = TriangleShapes | QuadShapes
type QuadShapes = "Trapezoid" | ParallelogramShapes
type ParallelogramShapes = "Square" | "Rectangle" | "Rhombus" | "Parallelogram"
type TriangleShapes = "Isosceles" | "Scalene" | "Equilateral"

现在,我们介​​绍通用的Meta

interface Meta {
    id: number
    number_of_sides: number,
    type: Shapes,
    is_quadrilateral: boolean, // Boolean is an object type, use boolean instead
    is_parallelogram: boolean, // ditto
}


interface QuadrilateralMeta extends Meta {
    number_of_sides: 4;
    type: QuadShapes;
    is_quadrilateral: true;
}

interface ParallelogramMeta extends QuadrilateralMeta {
    type: ParallelogramShapes;
    is_parallelogram: true;
}

interface TriangleMeta extends Meta {
    type: TriangleShapes;
    is_quadrilateral: false;
    is_parallelogram: false;
}

interface SquareMeta extends ParallelogramMeta {
    type: "Square"
    number_of_parallel_sides: 2; // not sure
}

可以通过指定通用的IShape并添加新属性来简明地描述interface IShape<M extends Meta> { $meta: M }

ISquare

最后是您的课程:

M

对您有用或给您带来想法的希望。祝你好运!

Link to code