强制泛型数组中的子类型

时间:2019-10-02 16:35:48

标签: typescript-generics

我正在尝试创建列列表,其中每个列都有我想由类型系统强制执行的约束。列渲染器具有通用的value属性,还具有valueGetter,应返回自定义渲染器的适当类型。

我的困难在于,当我声明数组时,我不知道每种类型将是什么,因此我求助于unknown,这使我对列的分配不强制类型。

export interface Grid<R> {
    // How can I specify that the second type param should be inferred from its usage?
    columns: GridColumn<R, unknown>[];
}

我的问题是:如何在value界面中推断GridColumn的类型

/**
 * R is the type of the whole record for current row
 * V is the type of `ColumnRenderer#value`
 */
export interface GridColumn<R, V> {
    renderer: ColumnRendererSpec<R, V>;
}

/** The component that will be dynamically instantiated */
export interface ColumnRenderer<V> {
    value: V;
}

interface ColumRendererConstructor<V> {
     new(...args: any[]): ColumnRenderer<V>;
}

interface ValueGetter<R,V> {
    (record: R): V
}

export interface ColumnRendererSpec<R, V> {
    type: ColumRendererConstructor<V>;

    /** Retrieves what is going to be passed to set ColumnRenderer#value  */
    valueGetter: ValueGetter<R, V>;
}

export interface Grid<R> {
    columns: GridColumn<R, unknown>[];
}

这就是我想要的称呼

export interface Icon {
    code: string;
    label: string;
}

export interface Tooltip {
    text: string;
    tooltipText: string;
}

/** Type of record being passed to this grid */
interface MyRecord {
  code: string;
  label: string;
  text: string;
  description: string;
}

/** Renderers */
@Component({template: `<p><clr-icon icon="value.code"></clr-icon>value.label</p>`})
export class IconRenderer implements ColumnRenderer<Icon> {
    value: Icon;
}
@Component({template: `<p [title]="value.tooltipText</p>value.text`})
export class TooltipRenderer implements ColumnRenderer<Tooltip> {
    value: Tooltip;
}


const grid: Grid<MyRecord> = {
    columns: [
        {
            renderer: {
                type: IconRenderer,
                // This is compiling but shouldn't because valueGetter should return an Icon                    // 
                valueGetter: (r) => 2,
            },
        },
        {
            renderer: {
                type: TooltipRenderer,
                // This doesn't compile, but I wish I didn't have to cast
                valueGetter: (r) => 2,
            },
        } as ColumnRendererSpec<MyRecord, Tooltip>,    
    ]
};

正如代码中的注释所表明的,我想强制执行valueGetter返回从ColumnRendererSpec#type的value属性推断出的正确类型

1 个答案:

答案 0 :(得分:1)

可能不是最好的方法,但是由于列渲染器实现interface ColumnRenderer<V>,并且由于V应该是valueGetters的返回类型,所以我们可以传递列渲染器的构造函数和{{1 }}方法作为实用程序方法的参数,该实用程序将创建渲染器spec对象,并有助于getter从传递给valueGetter的泛型中推断其返回类型。

示例:

ColumnRenderer