在泛型数组中强制执行子类型
Enforce sub-type in array of generics
我正在尝试创建一个列列表,其中每一列都有我希望由类型系统强制执行的约束。列渲染器有一个通用的 value
属性 并且还有一个 valueGetter
应该 return 适合自定义渲染器的类型。
我的困难是,当我声明数组时,我不知道每种类型是什么,所以我求助于 unknown
,这使得我对列的分配不强制类型。
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
的类型
/**
* 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
return 是从 ColumnRendererSpec#type
的值 属性[ 推断出的正确类型=20=]
可能不是最好的方法,但是,由于列渲染器实现了 interface ColumnRenderer<V>
,并且由于 V
应该是 valueGetters
的 return 类型,我们可以通过列渲染器构造函数和 valueGetter
方法作为实用程序方法的参数,该方法将创建渲染器规范对象并帮助 getter 从传递给 [=15= 的泛型推断其 return 类型].
示例:
function createColumnRendererSpec<R, V>(
ctor: ColumnRendererConstructor<V>,
valueGetter: (r: R) => V): ColumnRendererSpec<R, V> {
return {
type: ctor,
valueGetter
}
}
我正在尝试创建一个列列表,其中每一列都有我希望由类型系统强制执行的约束。列渲染器有一个通用的 value
属性 并且还有一个 valueGetter
应该 return 适合自定义渲染器的类型。
我的困难是,当我声明数组时,我不知道每种类型是什么,所以我求助于 unknown
,这使得我对列的分配不强制类型。
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
的类型
/**
* 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
return 是从 ColumnRendererSpec#type
的值 属性[ 推断出的正确类型=20=]
可能不是最好的方法,但是,由于列渲染器实现了 interface ColumnRenderer<V>
,并且由于 V
应该是 valueGetters
的 return 类型,我们可以通过列渲染器构造函数和 valueGetter
方法作为实用程序方法的参数,该方法将创建渲染器规范对象并帮助 getter 从传递给 [=15= 的泛型推断其 return 类型].
示例:
function createColumnRendererSpec<R, V>(
ctor: ColumnRendererConstructor<V>,
valueGetter: (r: R) => V): ColumnRendererSpec<R, V> {
return {
type: ctor,
valueGetter
}
}