Reputation: 67698
I am new to typescript and I am trying to create a "model" class.
The constructor should accept a list of properties (that come from the database), and any of them should be optional.
Here is the code so far:
export type UserRole = "admin" | "moderator" | "user" | "visitor";
export default class User{
public id: number | null = null;
public login: string = '';
public email: string = '';
public role: UserRole = 'visitor';
...
constructor({id, login, email, role, ... }){
this.id = id;
this.login = login;
this.email = email;
this.role = role;
....
}
As you can see, it doesn't look right. A lot of code is duplicated. And if I want to make the properties optional it will duplicate even more code:(
Can anyone point me in the right direction? thanks
Upvotes: 0
Views: 3045
Reputation: 74234
Here's how I would implement the User
class.
type UserRole = 'admin' | 'moderator' | 'user' | 'visitor';
class User {
constructor(
public id: number | null = null,
public login: string = '',
public email: string = '',
public role: UserRole = 'visitor'
) {}
}
However, if you want to create the instance of the User
class from an object of user properties then you will require some duplication.
type UserRole = 'admin' | 'moderator' | 'user' | 'visitor';
interface UserProps {
id: number | null;
login: string;
email: string;
role: UserRole;
}
class User implements UserProps {
constructor(
public id: number | null = null,
public login: string = '',
public email: string = '',
public role: UserRole = 'visitor'
) {}
static fromProps({ id, login, email, role }: Partial<UserProps> = {}) {
return new User(id, login, email, role);
}
}
There's no elegant way around this duplication. Tobias S. and jcalz show hacks to avoid this duplication, but I would discourage you from using such hacks.
Upvotes: 2
Reputation: 23865
I would suggest to use following utility type from here:
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T];
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
This will create a type
out of all properties of a class
without the methods.
You can use it like this:
export type UserRole = "admin" | "moderator" | "user" | "visitor";
export default class User{
public id: number | null = null;
public login: string = '';
public email: string = '';
public role: UserRole = 'visitor';
constructor({id, login, email, role }: NonFunctionProperties<User>){
this.id = id;
this.login = login;
this.email = email;
this.role = role
}
}
To make them all optional, just add Partial
:
constructor({id, login, email, role }: Partial<NonFunctionProperties<User>>)
Upvotes: 2