Alexander Mills
Alexander Mills

Reputation: 100210

DRY with TypeScript and constructor that takes options object

I have this code:

export interface LDAPPoolOpts {
  id: number;
  size: number;
  connOpts: any;
  active: Array<any>;
  inactive: Array<any>;
  dn: string;
  pwd: string;
  waitingForClient: Array<Function>
}


export class Pool {

  id: number;
  size: number;
  connOpts: any;
  active: Array<any>;
  inactive: Array<any>;
  dn: string;
  pwd: string;
  waitingForClient: Array<Function>;

  constructor(opts: LDAPPoolOpts) {}

 }

as you can see the constructor for this class simply takes an options object with type: LDAPPoolOpts.

My question is: how can avoid repeating myself by having to declare the exact same fields for both the class and the options object interface?

You cannot extend an interface..and implementing an interface does not mean you inherit the interface's fields.

Should I declare a type instead of an interface?

Upvotes: 3

Views: 889

Answers (3)

Volodymyr Bobyr
Volodymyr Bobyr

Reputation: 424

2020 UPDATE

Now it's possible to do what you want with minimal boilerplate:

interface LDAPPoolOpts {
    id: number;
    size: number;
    connOpts: any;
    active: Array<any>;
    inactive: Array<any>;
    dn: string;
    pwd: string;
    waitingForClient: Array<Function>
}

interface Pool extends LDAPPoolOpts { }
class Pool {
    // Pool has all the properties of LDAPPoolOpts
    // no need to copy stuff over
}

// if you want to export, make sure its on a different line
export default Pool;

https://github.com/Microsoft/TypeScript/issues/340#issuecomment-184964440

Upvotes: 1

John Weisz
John Weisz

Reputation: 31982

What I frequently use is the following:

export class Pool {
    // ...

    constructor(initializer?: Partial<Pool>) {
        if (initializer) {
            Object.assign(this, initializer)
        }
    }
}

This, of course, assumes that the class has the same properties as the supposed initializer object, so this is essentially very similar to object initialization in C#. This approach works best if you are also initializing your instance members to meaningful default values.

Upvotes: 2

Andrew Sinner
Andrew Sinner

Reputation: 1881

You are correct in that you cannot extend an interface and implementing the interface requires you to write out the properties again. Although this solution alters the structure of your class, one way is to create a property on the class with the interface type.

export interface LDAPPoolOpts {
    id: number;
    size: number;
    connOpts: any;
    active: Array<any>;
    inactive: Array<any>;
    dn: string;
    pwd: string;
    waitingForClient: Array<Function>
}


export class Pool {
     opts: LDAPPoolOpts;

     constructor(opts: LDAPPoolOpts) {
         this.opts = opts; // assign to the property how you see fit
     }
}

Upvotes: 2

Related Questions