Home > Enterprise >  create a chainable private variable without having to create public functions for all of them
create a chainable private variable without having to create public functions for all of them

Time:09-19

I wonder if there are any syntax/design patterns to achieve the following:

Consider a class like this:

Class myClass{
 private a: int;
 private b: int;
 private c: int;
 private d: int;  
  ...
 //20 more private variables
}  

I basically want to do this:

 const x = new myClass().a(32).b(34).c(56);

which would basically create a class whose a=32, b=34, c=56;

The only way I know is to create public functions:

Class myClass{
  public a(val: int){  
   a = val;
   return this;
  }  

  public b(val: int){  
   b = val;
   return this;
  }    

  public c(val: int){  
   c = val;
   return this;
  }   
  ...//for 20 more rows :-(
}  

As you can see this would be very repetitive, yes ofcourse I could do this:

Class myClass{
 set properties({a, b, c, d, e, ...//more vars}: any) {
  this.a = a;
  this.b = b;  
  //others
  }
}  

But, I'd like to achieve this syntax:

 const x = new myClass().a(32).b(34).c(56);  

Because, it's much cleaner and makes sense for my usecase, where I'll only ever be overriding a handful of values.

Is there any way in nodejs/typescript I can achieve this avoiding the constrains mentioned above?

CodePudding user response:

This isn't in the exact format you asked about, but it's just as terse and type safe:

TS Playground

const myClassKeys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] as const;
type MyClassKey = typeof myClassKeys[number];

class MyClass {
  private values: Partial<Record<MyClassKey, number>> = {};

  set = (key: MyClassKey, int: number): this['set'] => {
    this.values[key] = int;
    return this.set;
  }
}

const myClass = new MyClass();
myClass.set('a', 32)('b', 34)('c', 56);

console.log(JSON.stringify(myClass)); // {"values":{"a":32,"b":34,"c":56}}

CodePudding user response:

As mentioned in the comment your class structure is ambiguous. What type are your properties? are they numbers or are they methods? Are they either one or the other or are they both at the same time? I'm sure you can somehow hack something close to that together but I don't see the purpose.

I'd go with a typeguarded Object.assign().

type Props<T> = {
  [P in keyof T]: T[P] extends (...args:any[]) => any ? never : T[P];
}

class MyClass {
  // for once make these properties public if you want to access them from the outside.
  public a: number;
  public b: number;
  public c: number;
  public d: number;

  // a method that nags if you try to assign something invalid to the instance.
  // this ain't fool-proof but it should provide enough type safety.
  public set(props: Partial<Props<MyClass>>): this {
    return Object.assign(this, props);
  }
}

const x = new MyClass().set({ a:32, b:34, c:56 });  
  • Related