【问题标题】:Extending Multiple Interfaces or Creating new Classes in Typescript (Polymorphism)在 Typescript 中扩展多个接口或创建新类(多态)
【发布时间】:2020-03-14 01:46:35
【问题描述】:

我开始在 typescript 中对 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

【问题讨论】:

    标签: typescript class interface polymorphism


    【解决方案1】:

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

    首先我会重写你的类型。请注意,为了保持一致性,我认为您希望Shapes 成为TriangleShapes | QuadShapes,因为子类型化要求如果Square 实现IShape,则type 属性可以分配给IShapetype 属性。但是"Square" 不能分配给"Parallelogram" | "Triangle",因为这些是string literal 类型并且只引用特定的字符串:

    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 并添加新属性来简明地描述:

    interface ISquare extends IShape<SquareMeta> {
        name: string;
        color: string;
    }
    

    最后是你的班级:

    class Square implements ISquare {
        constructor(public $meta: SquareMeta, public name: string, public color: string) { }
    }
    

    希望对您有用或给您一些想法。祝你好运!

    Link to code

    【讨论】:

    • 所以这很好用!谢谢您的帮助。一个问题,我可能在这里添加了一个不必要的抽象级别,但是 Meta 是通用的:例如 Meta&lt;T&gt; 其中 type 被设置为通用 Shapes
    • 我不太了解用例,无法就使Meta 和/或Shapes 通用化是否值得发表意见。
    • 对...我掉进了那个兔子洞,它变成了泛型地狱。所以我决定 4 或 5 个接口会更容易。再次感谢您!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2012-04-20
    • 2018-06-20
    • 1970-01-01
    • 2020-12-28
    • 2016-07-06
    相关资源
    最近更新 更多