I'm making a query builder. I have data models that look like this:
export interface SalesOrder {
id: number
customerName: string;
date: Date;
}
In my query builder, I want to have the columns
look something like this:
{
id: 'salesOrder.id',
customerName: 'customer.name',
date: 'salesOrder.date',
}
I'm trying to figure out how I can type the Columns
object generically so that it will have all the keys from the model, but all of the types will be a string. So then I would be able to declare it like const columns: Columns<SalesOrder>
and it would understand that the object must have all the same keys as in the SalesOrder
model, but with all the values being string
.
I tried this:
export interface Columns<T> {
[alias: keyof T]: string;
}
But it complains about the keyof T
part, saying "An index signature parameter type must be either 'string' or 'number'."
CodePudding user response:
The end of that error message should have been:
Consider using a mapped object type instead.
See the documentation on mapped types.
Here's what that means:
export type Columns<T> = {
[alias in keyof T]: string;
}
It needs to be a type
, because this is actually a mapped type. It walks all possibilities of keyof T
and evaluates each member of that union individually. This isn't really supported in interfaces.
And [key: MyType]
is an index signature. It says that for any MyType
there is a value of a consistent type. Where [key in MyType]
define the keys of a mapped type.
Alternatively, you could try the Record
type.
export type Columns<T> = Record<keyof T, string>