I have an idea for creating a versatile class named Model. Here's what I have in mind:
export class Model {
_required_fields: Array<string> = [];
_optional_fields?: Array<string> = [];
constructor(params: Dictionary<string> = {}) {
// Ensure all required fields are present in the params object
}
set(params: Dictionary<string>){
// Verify that only required or optional fields are included
this.all_fields.forEach(key => {
this[key] = params[key];
});
}
get all_fields(): Array<string> {
return [...this._required_fields,...this._optional_fields];
}
get required_fields() {
return this._required_fields;
}
}
Children of this class will specify the required and optional fields. I've kept the code concise by implementing error checking in the set
method. For instance:
export class User extends Model {
static REQUIRED_FIELDS = ['username'];
static OPTIONAL_FIELDS = ['email'];
get required_fields() {
return (this._required_fields?.length==0) ? User.REQUIRED_FIELDS : [];
}
static get ALL_FIELDS() {
return [...User.REQUIRED_FIELDS, ...User.OPTIONAL_FIELDS];
}
constructor(params: Dictionary<string> = {}) {
super(params);
}
}
I have defined a version of User
with fields:
username: string;
email: string;
However, I want to be able to define the fields dynamically so that the set
function can populate them based on a Dictionary
.
The TypeScript error I'm encountering is
No index signature with a parameter of type 'string' was found on type 'Model'
at the line:
this[key] = params[key];
This issue arises because I need to include a field like: [key: string]: string;
within the Model
definition.
There appear to be two potential solutions for this problem:
Method 1: Explicitly defining each field inside of User
, and manually assigning values within the set
method (of User
) as follows:
user.username = params.username;
user.email = params.email;
Although this approach works, it involves repetitive coding for all children of Model, which contradicts my goal of automating some error checks.
Method 2: Alternatively, retaining a generic field within the Model:
[key: string]: string;
This allows the existing set
implementation to function without direct access to fields such as user.username
, but rather user['username']
.
Summary
Thus far, I've followed Method 1, resulting in extensive duplicated code across child classes of Model
. This repetitiveness isn't ideal, considering I may have multiple fields to manage. Is there a more efficient way to structure this logic within the Model
class itself?
Though Method 2 offers brevity, it sacrifices some of TypeScript's strong typing capabilities. While compact, this compromise doesn't seem optimal.
Question
Is there a middle ground where I can combine TypeScript's robust typing with the convenience of Method 1?