我具有以下接口来定义定义表的列:
export interface IColumnDefinition<TRow, TField extends keyof TRow> {
field: TField;
label?: string;
formatter?: (value: TRow[TField], row: TRow) => string;
}
现在我只想提供行的类型(TRow
,然后让TypeScript根据{{1 }}属性。
现在假设我的行具有以下界面:
TField
我尝试的是以下内容:
field
这给了我以下错误:
通用类型“ IColumnDefinition
”需要2个类型的参数。
我还尝试使用函数创建定义,希望可以从参数中推断出类型:
interface User {
name: string;
birthDate: number;
}
这给了我一个类似的错误:
除了2个类型参数外,但得到1个。
但是,如果我还将行作为参数包含在内,并且一起删除所有通用参数,则效果很好:
const birthDateColumnDefinition: IColumnDefinition<User> = {
field: 'birthDate',
formatter: value => new Date(value).toDateString(),
}
这确实有效,但这不是一个选择,因为定义列时我实际上没有一行。
那么有什么方法可以做到这一点(最好是使用接口而不是函数)?
答案 0 :(得分:1)
现在我只想提供行的类型(TRow),并且 让TypeScript自动推断字段的类型(TField) 基于字段属性中的值。
这看起来与partial type inference非常相似,目前打字稿中尚不支持,目前尚不清楚此特定用例是否会支持它。
但是您可以做一件事-您可以使一个函数接受TRow
的显式类型参数,然后返回另一个函数,该函数将从其参数推断TField
。语法有点笨拙,但可以使用:
function columnDefinition<TRow>():
<TField extends keyof TRow>(def: IColumnDefinition<TRow, TField>) =>
IColumnDefinition<TRow, TField> {
return <TField extends keyof TRow>(def: IColumnDefinition<TRow, TField>) => def
}
export interface IColumnDefinition<TRow, TField extends keyof TRow> {
field: TField;
label?: string;
formatter?: (value: TRow[TField], row: TRow) => string;
}
interface User {
name: string;
birthDate: number;
}
要使用它,请不带任何参数调用columnDefinition<User>()
,然后立即以列定义对象作为参数调用返回的函数:
const birthDateColumnDefinition = columnDefinition<User>()({
field: 'birthDate',
formatter: value => new Date(value).toDateString(),
// value inferred as (parameter) value: number
});
答案 1 :(得分:0)
我最终使用artem的答案编写了一个列定义构建器类:
export class ColumnDefinitionBuilder<TRow> {
private _columns: Array<IColumnDefinitionWithField<TRow, any>> = [];
public define<TValue>(field: ((row: TRow) => TValue) | string, def: IColumnDefinition<TRow, TValue>)
: ColumnDefinitionBuilder<TRow> {
this._columns.push({...def, field});
return this;
}
public get columns() {
return this._columns;
}
}
允许使用以下语法定义列:
const userColumnDefinitions = new ColumnDefinitionBuilder<User>()
.define(x => x.birthDate, {
label: 'Birth date',
formatter: x => new Date(x).toDateString(),
})
.define(x => x.name, {
label: 'Name',
})
.columns;