I am trying to define a type based on ColDef<TData> which infers the type of valueFormatter from the given value of field. For example, consider the following Order type:
type Order = {
id: string,
product: string,
quantity: number,
timestamp: Date,
}
When defining a table of Order rows in an Angular project, the column definitions will look something like:
const gridOptions: GridOptions<Order> = {
// Define 3 columns
columnDefs: [
{ field: 'id' },
{ field: 'product' },
{
field: 'quantity',
// params has inferred type ValueFormatterParams<Order, any>
// a stricter type would be ValueFormatterParams<Order, number>
valueFormatter: (params) => params.value.toLocaleString(),
},
],
// Other grid options...
};
My issue is that nothing stops me from adding the following column definition:
{
field: 'timestamp',
// Wrong type for params! The runtime type of params.value will be Date, not number!
valueFormatter: (params: ValueFormatterParams<Order, number>) => `${params.value + 1}`,
}
I want the above code to raise a type error from the incorrect type parameters. Is there any way to tell TypeScript that the type of valueFormatter should be determined by the value of the given field property?
I want something to this effect:
type StrictColDef<TData> = ColDef<TData> & {
field: TProperty extends keyof TData, // This gets inferred somehow
valueFormatter?: (params: ValueFormatterParams<TData, TData[TProperty]>): string,
};
type StrictGridOptions<TData> = GridOptions<TData> & { columnDefs: StrictColDef<TData>[] };
const gridOptions: StrictGridOptions<Order> = {
// Define 3 columns
columnDefs: [
{ field: 'id' },
{ field: 'product' },
{
field: 'quantity',
// params now has inferred type ValueFormatterParams<Order, number>, yay!
valueFormatter: (params) => params.value.toLocaleString(),
},
{
field: 'timestamp',
// type error because the compiler has inferred type for params.value: Date
valueFormatter: (params) => `${params.value + 1}`,
},
],
// Other grid options...
};
I've tried doing exactly this, but it just isn't how types are constructed in TypeScript.
I got a solution using type mapping! I wish there was a way to do this kind of type inference natively, but this is a pretty minimal workaround.
Playground link