I'm working with TypeScript and I need to deal with dynamic object properties. I wish that I could be a master in TypeScript but I am not. The problem I have is that in my current project, I would like to give users the possibility to input their own custom interface to a Generic interface.
What I got working now is the following interface
export interface Filter {
columnId: string;
searchTerm: string;
}
export interface GridState {
filters: Filter[];
}
// use it as an array of filters
const state: GridState = {
filters: [{ columnId: 'firtName', searchTerm: 'John' }]
}
However from what is shown above, I would like to give the user the possibility to use his own interface. So let say that instead of columnId
, he wants to use field
and instead of searchTerm
he would use value
. So his custom interface would be
export interface CustomFilter {
field: string;
value: string;
}
What I would like to provide to the user is something like this, a custom structure template
export interface FilterStruct {
propNameColumnId: string;
propNameSearchTerm: string;
}
but how do I connect the 2 together? How do I use the user's CustomFilter
with the FilterStruct
. The following doesn't work and I know it's not correct.
export interface GridState {
filters: FilterStruct<CustomFilter>[];
}
The end goal is that the user would be able to input with his own interface and his own property names. Then on my side, I would just loop through the array with the dynamic object property that was provided.
You can make GridState
generic and provide a default value for the generic parameter. Also FilterStruct
can inherit Array
, so we can add extra properties to the array, using a helper function :
export interface FilterStruct<T> extends Array<T> {
// We make sure the property names are actually properties of T
// We make these optional you should use default values if they are undefined
// We do this to keep initialization simple in the non customized scenario, you can make them mandatory, but then you can't initialize with a simple array
propNameColumnId?: keyof T;
propNameSearchTerm?: keyof T;
}
export interface Filter {
columnId: string;
searchTerm: string;
}
export interface CustomFilter {
field: string;
value: string;
}
// T has a default value of Filter so we don't have to specify it, unless we want to customize
export interface GridState<T = Filter> {
filters: FilterStruct<T>;
}
// Helper function to create an array with the extra properties
function createFilterStruct<T>(cfg: { propNameColumnId: keyof T; propNameSearchTerm: keyof T; }, items: T[]) {
return Object.assign(items, cfg);
}
// Default we can use simple array initailization
const state: GridState = {
filters: [{ columnId: 'firtName', searchTerm: 'John' }]
}
// Custom filter, create with createFilterStruct
const stateCustom: GridState<CustomFilter> = {
filters: createFilterStruct({ propNameColumnId: 'value', propNameSearchTerm: 'field' }, [
{ value: 'firtName', field: 'John' }
])
}
//Usage
function loopThrough<T>(grid: GridState<T>){
// Provide defaults for propNameColumnId and propNameSearchTerm
let propNameColumnId = grid.filters.propNameColumnId || 'columnId' as keyof T
let propNameSearchTerm = grid.filters.propNameSearchTerm || 'searchTerm' as keyof T
// Loop throught the array normally, it is just an array
for(let filter of grid.filters){
// Access the properties
console.log(`${filter[propNameColumnId]} = ${filter[propNameSearchTerm]}`);
}
}
loopThrough(stateCustom);
loopThrough(state);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.