I am trying to develop an independent component using ag-grid. I will pass the column definitions to this independent component from my application so I set it up as an input property with a type like this:
interface ColumnDef {
field: string;
headerName: string;
}
@Input() colDef: ColumnDef[];
Now as you can see I can pass any number of columns I want from my host(where i will use this common component) application with a different id and that is working fine.
Now the requirement is I want to define the type for row data for ag-grid inside the common component dynamically also.
Suppose i pass column defs as:
[{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'}]
So when the component receive this column defs, it should create dynamically a row data type as
interface rowData {
colA: string;
colB: string;
}
Similarly if i pass column definitions as
[{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'},
{field: 'colC', headerName: 'Col C'}]
the row data type should be crated as
interface rowData {
colA: string;
colB: string;
colC: string;
}
so that I can use this interface to type my row data. Is there any way to implement this?
Thanks in advance.
Given some array like this:
const colDef = [{field: 'colA', headerName: 'Col A'},
{field: 'colB', headerName: 'Col B'},
{field: 'colC', headerName: 'Col C'}] as const;
we can have these types:
type FieldNames<T> = T extends ReadonlyArray<{ field: infer U }> ? U : never;
type Rows<T> = FieldNames<T> extends string ? Record<FieldNames<T>, string> : never;
so that both
FieldNames<typeof colDef>
is 'colA' | 'colB' | 'colC'
Rows<typeof colDef>
is { colA: string; colB: string; colC: string }
.However, with your current ColumnDef
type, typeof colDef
is ColumnDef
, and so FieldNames<typeof colDef>
will be Record<string, string>
, which is not particularly helpful. To fix this, we will need to add a type parameter to the component class like so:
class CustomGridComponent<T extends ColumnDef> implements OnInit /* or what have you */ {
@Input() colDef: ReadonlyArray<T> = [] as const;
...
}
(by the way, using ReadonlyArray
lets you get the types of your column definitions 'for free' by adding as const
after the end of your array. If you are fine with manually defining some interface ABCColDef { field: 'colA' | 'colB' | 'colC'; ... }
then ReadonlyArray
is not necessary.)