本文介绍了在泛型数组中强制执行子类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a list of columns where each column has constraints that I would like enforced by the type system. A column renderer has a generic value property and also has a valueGetter that should return the appropriate type for the custom renderer.

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

My difficulty is that when I declare the array, I don't know what each of the types is going to be so I'm resorting to unknown which makes my assignment to columns not enforce types.

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

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

My question is: how can I infer the type of value in my GridColumn interface

/**
 * 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 属性推断出的正确类型

As my comments in the code indicate, I'd like to enforce that valueGetter returns the correct type inferred from ColumnRendererSpec#type's value property

推荐答案

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

Might not be the best way but, since the column renderers implement interface ColumnRenderer<V> and since V should be return type of valueGetters, We can pass the column renderer constructor and valueGetter method as parameters to a utility method that would create the renderer spec object and that would help the getter to infer its return type from the generic passed to ColumnRenderer.

示例:

  function createColumnRendererSpec<R, V>(
     ctor: ColumnRendererConstructor<V>,
     valueGetter: (r: R) => V): ColumnRendererSpec<R, V> {
         return {
             type: ctor,
             valueGetter
         }
     }

这篇关于在泛型数组中强制执行子类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 18:09