26

I have an Object where I use it in multiple services, and each one should take some parameters, so I create two constructors, but TypeScript did not allow me to do this. My example is:

class User {
    id: number;
    username: string;
    password: string;
    email: string;
    firstName: string;
    lastName: string;
    roles: string[];

    constructor(username: string, password: string){
        this.username = username;
        this.password = password;
    }

    constructor(id: number, username: string, firstname: string, lastname: string, roles: string[]){
        this.id = id;
        this.username= username;
        this.firstname= firstname;
        this.lastname= lastname;
        this.roles = roles;
    }
    //.. and maybe another constructor also
}

Is there a trick to solve this issue, please?


When I use the optional ? in constructors for example:

constructor(
    public id?: number,
    public username?: string,
    public email?: string,
    public password?: string,
    public firstName?: string,
    public lastName?: string,
    public roles?: string[]) {
}

and when I get my data from backend:

this.service.usersList().subscribe(users => {
  console.log(users);
  this.dataSource.data = users;
});

The roles is set in the password and not in the roles failed:

{
  "id": 1,
  "username": "user1",
  "email": "user1@email.com",
  "password": [
    "USER",
    "MODR"
  ]
}

For that I'm not sure about this trick.


Maybe I was not precise, but I use this method to parse my data:

static fromJson(item: Object): any {
    return new User(
        item['id'],
        item['username'],
        item['email'],
        item['roles']
    );
}

For that, when I create a constructor with optional, it will set the attributes in order of my call.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Doesn't Matter
  • 1,061
  • 3
  • 11
  • 29
  • Typescript allows only 1 constructor. You can use the `?` optional parameter. Which fields will be mandatory always? – Nicholas K Apr 11 '20 at 09:29
  • @NicholasK I know that typescript allow only one constructor, but in my case I need multiple ones, and if I use `?` for optional, it fail in some cases – Doesn't Matter Apr 11 '20 at 09:31
  • You can use `optional parameters` , and verify if the needed parameters exists to implement one of the two constructors , see my answer below – Aymen TAGHLISSIA Apr 11 '20 at 09:31
  • Explain those *cases* so we can give you a *better* answer. – Nicholas K Apr 11 '20 at 09:32
  • You cannot have multiple implementations of one and the same method in JS. You can however declare overload signatures for them in TypeScript, [even for constructors](https://stackoverflow.com/questions/12702548/constructor-overload-in-typescript). – Bergi Jun 12 '21 at 18:36
  • **This question already has an answer at:** [TypeScript - Multiple constructor implementations are not allowed (for Copy-Constructor)](https://stackoverflow.com/questions/54613663/typescript-multiple-constructor-implementations-are-not-allowed-for-copy-cons) – Top-Master Dec 07 '21 at 16:53

3 Answers3

28

You can't use multiple constructors, but you can add a few optional parameters and verify if it exists, like the following:

class User {
    id: number;
    username: string;
    password: string;
    email: string;
    firstname: string;
    lastname: string;
    roles: string[];
    // The "?" says that its optional parameter
    constructor(id?: number, username?: string, firstname?: string,
        lastname?: string, roles?: string[], password?: string) {
        if (id) { // if id exists , you can implement the first constructor
            this.id = id;
            this.username = username;
            this.firstname = firstname;
            this.lastname = lastname;
            this.roles = roles;
        }
        if (password) { // if password exists : you can implement the second one
            this.username = username;
            this.password = password;
        }
    }
}

Your response should be like this before this works fine:

static fromJson(item: Object): any {
    return new User({
        id : item['id'],
        username : item['username'],
        email : item['email'],
        roles : item['roles']
    });
}

So your constructor should be like this:

constructor(user: any){
    if (user.id) { // if id exists , you can implement the first constructor
        this.id = user.id;
        this.username = user.username;
        this.firstname = user.firstname;
        this.lastname = user.lastname;
        this.roles = user.roles;
    }
    if (user.password) { // if password exists : you can implement the second one
        this.username = user.username;
        this.password = user.password;
    }
}

Or if you don't want to do that, you can set the response regarding the order, like this:

static fromJson(item: Object): any {
    return new User(
        item['id'],
        item['username'],
        undefined,
        item['email'],
        undefined,
        undefined,
        item['roles']
    );
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aymen TAGHLISSIA
  • 1,675
  • 13
  • 30
  • Thank you @Aymen, When I try your solution I have the problem where roles are seted in lastName and not in roles failed `{ "id": 1, "username": "user1", "firstName": "user1@email.com", "lastName": [ "USER", "MODR" ] }` – Doesn't Matter Apr 11 '20 at 09:47
  • In the backend I send an Object which hold this different attributes, but when it come to the frontend, the Object is not set correctly. – Doesn't Matter Apr 11 '20 at 09:54
  • 1
    Ok, I fix it, I add the roles in the constructor – Doesn't Matter Apr 11 '20 at 09:58
  • Sorry, But as I said the roles is seted in lastName and not in roles, and this I don't understand why typescript do this, It is not your mistake, but your solution is not working – Doesn't Matter Apr 11 '20 at 10:05
  • I edit my question, and I add another part, maybe it can help you to understand what happen with me – Doesn't Matter Apr 11 '20 at 10:08
  • I found my mistake and I solve it, you can check my answer below. – Doesn't Matter Apr 11 '20 at 10:17
  • to use multiple constructors , you need to have an object with specific names , so you can't just use attributes order to define them , you can change the type of return , i'll do an update to my answer – Aymen TAGHLISSIA Apr 11 '20 at 10:22
  • Your trick look like very nice, should I change the constructor, because It doesn't work with the existing one, it show me: `Argument of type '{ id: any; username: any; email: any; roles: any; }' is not assignable to parameter of type 'number'` – Doesn't Matter Apr 11 '20 at 10:32
  • Thank you for your help, you deserve it :) – Doesn't Matter Apr 11 '20 at 10:54
  • Yes it do, I'm new in typescript, so I don't know if it is good practice or not, but yes it works – Doesn't Matter Apr 11 '20 at 10:56
1

I found the solution:

What happened?

When you create a constructor with optional parameters and try to call this constructor, it will set the attributes with the order of call. For that, when I call:

new User(
    item['id'],
    item['username'],
    item['email'],
    item['roles']
);

The roles in set in the firstName or password.

Solution

To solve this, it's required to change the order or parameters in the constructor:

constructor(
    public id?: number,
    public username?: string,
    public email?: string,
    public roles?: string[],

    public password?: string,
    public firstName?: string,
    public lastName?: string) {
}

Or if you won't change the order, just use undefined for example:

new User(
    item['id'],
    item['username'],
    undefined,
    item['email'],
    undefined,
    undefined,
    item['roles']
);

Until you arrive to the position of your attribute.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Doesn't Matter
  • 1,061
  • 3
  • 11
  • 29
-6

Use:

export class A {
   constructor() {
      // Something here
   }
   secondConstructor() {
      // Something here
      return this;
   }
}

And then you use just like this:

const a = new A();
const a2 = new A().secondConstructor();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Faradox
  • 183
  • 2
  • 14
  • An explanation would be in order. E.g., what is the idea/gist? From [the Help Center](https://stackoverflow.com/help/promotion): *"...always explain why the solution you're presenting is appropriate and how it works"*. Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/67951614/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Oct 28 '22 at 16:03