首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于打字本中的类型、地图和子类的问题

关于打字本中的类型、地图和子类的问题
EN

Stack Overflow用户
提问于 2021-10-27 11:48:06
回答 1查看 88关注 0票数 1

我有一个Chart类,它有几个子类(BarChartTimeseriesChart.)它扩展了Chart。我使用一个名为buildChart的方法来构建这些图表。它使用Map将枚举ChartsEnum (例如,stackedTimeseriesbarChart)映射到正确的类:

代码语言:javascript
复制
export function buildChart(type: Charts, data: Array<TimeseriesData>) {
   
   var chartsMap = new Map<Charts, InstantiableAbstractClass<typeof Chart>([
        [Charts.stackedTimeseries, TimeseriesChart],
        [Charts.barChart, BarChart],
    ])
    const chart = chartsMap.get(type)
    return new chart(data).chart;

}

InstantiableAbstractClass类型如下所示:

代码语言:javascript
复制
export declare type InstantiableClass<T> = (new ( ...args: any) => { [x: string]: any }) & T;

例如,TimeseriesChart的类和构造函数如下所示:

代码语言:javascript
复制
export class TimeseriesChart extends Chart{
    constructor(data: Array<TimeseriesData>) {
        super(data);
    }
}

现在,我想向chart-class添加第二个属性,名为options (在现有属性data旁边)。现在的问题是,options需要针对每个ChartType (BarChartTimeseriesChart)不同的属性。例如,BarChart需要以下属性:

代码语言:javascript
复制
{
    start: number;
    end?: number;
}

TimeseriesChart需要这样的类型:

代码语言:javascript
复制
{
    description: string;
}

然后,TimeseriesChart的构造函数将如下所示:

代码语言:javascript
复制
export class TimeseriesChart extends Chart{
    constructor(data: Array<TimeseriesData>, options: TimeseriesChartOptions) {
        super(data, options);
    }
}

这意味着方法buildChart需要一个新的参数options,然后这个参数options可以传递给特定的类(就像参数data所做的那样)。

做这件事最好的方法是什么?我考虑过使用泛型,然后为n个子类为options定义n种类型,但我想不出如何正确地更改InstantiableAbstractClass类型。

您可以找到一个完整的示例,其中包含一些描述这里

我真的很感激你的帮助!如果您需要更多的信息,我很乐意提供他们。

谢谢你和所有最棒的卢卡斯

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-30 20:19:52

首先,您似乎希望您的Chart类是abstract,因为您只打算使用它的具体子类,如果没有重写,您希望抛出buildChart()方法。我还将使用参数性质作为声明字段和idential构造函数参数的缩写,并将后者分配给前者。我在添加一个options参数类型,因为我们实际上不需要在基类中像这样检查任何类型。

代码语言:javascript
复制
abstract class Chart {
    constructor(protected data: Array<TimeseriesData>, protected options: any) { }
    abstract buildChart(): void;
}

无论如何,对于子类,我们将通过使用options属性修饰符属性缩小到适当的类型,并在构造函数参数中指定该类型:

代码语言:javascript
复制
interface BarChartOptions {
    start: number,
    end: number
}
class BarChart extends Chart {
    declare options: BarChartOptions;
    constructor(data: Array<TimeseriesData>, options: BarChartOptions) {
        super(data, options);
    }
    buildChart() { return {}; }
    protected getChartData() { }
}


interface TimeseriesChartOptions {
    description: string
}

class TimeseriesChart extends Chart {
    declare options: TimeseriesChartOptions;
    constructor(data: Array<TimeseriesData>, options: TimeseriesChartOptions) {
        super(data, options);
    }
    buildChart() { return { }; }
    protected getChartData() { }
}

现在,我们需要表达Charts枚举和不同子类之间的关系。让我们让一个包含枚举的chartConstructors对象作为键,构造函数作为值:

代码语言:javascript
复制
const chartConstructors = {
    [Charts.stackedTimeseries]: TimeseriesChart,
    [Charts.barChart]: BarChart
}

您应该为您所关心的Chart的每个子类添加一个条目。

最后,我们将编写您的buildChart()函数。让我们做一些助手类型:

代码语言:javascript
复制
type ChartConstructorParameters<C extends Charts> = 
  ConstructorParameters<typeof chartConstructors[C]>;
type ChartInstance<C extends Charts> = 
  InstanceType<typeof chartConstructors[C]>;
type ChartConstructor<C extends Charts> = 
  new (...args: ChartConstructorParameters<C>) => ChartInstance<C>;

ChartConstructorParameters<C>类型将接受枚举成员作为C,并使用实用程序类型将其转换为相关的类构造函数的元组论点

ChartInstance<C>类型使用实用程序类型对相关类构造函数的实例类型执行相同的操作。

最后,ChartConstructor<C>表示该类的相关构造器签名

现在是buildChart()

代码语言:javascript
复制
function buildChart<C extends Charts>(
  type: C, ...ctorArgs: ChartConstructorParameters<C>
) {
    const chartConstructor = chartConstructors[type] as ChartConstructor<C>;
    return new chartConstructor(...ctorArgs);
}

它是一个属函数,它接受与枚举成员对应的泛型类型Ctype参数。对于其余的参数,它接受相关类的构造函数参数。这将是一对dataoptions,用于BarChartTimeseriesChart,但是如果添加带有其他构造函数参数的子类,它将接受这些子类。

输出是类的一个实例,它通过从chartConstructors获取相关的构造函数来构造这个类(我们需要使用类型断言来使编译器确信chartConstructors[type]实际上是ChartConstructor<C>类型;这是编译器无法看到的,因为它无法对未指定的泛型(如C)进行过多的推理)。

那么它起作用了吗?

代码语言:javascript
复制
const barChart = buildChart(Charts.barChart, [], { start: 1, end: 2 });
// const barChart: BarChart

const timeSeriesChart = buildChart(Charts.stackedTimeseries, [], { description: "" });
// const timeSeriesChart: TimeseriesChart

是的,看上去不错!

操场链接到代码

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69738102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档