1

I have a method in typescript as below using named parameters

public foo({x, y, z , m , n} : {x:string, y: number, z: number, m?:string, n?:number}) {
}

parameters m and n will be provided from another object like

const default = { m : 'M', n :10, o:6 }

Now I want to call foo like below and I want default parameters will be added without explicitly passing them in the call

  foo({x:'x', y: 5, z: 0})

So my question is how to apply default in the body of foo or somehow intercepting foo before call and apply default

public foo({x, y, z , m , n} = {x:string, y: number, z: number, m?:string, n?:number}) {
   // for example how to apply default here

}

Please note for simplicity I reduced number of parameters

Also I know these below solutions already I am looking for something with less boilerplate code

public foo({x, y, z , m , n} = {x:string, y: number, z: number, m?:string, n?:number}) {
   if (!m) {
     m = default.m;
   }
   if (!n) {
     n = default.n;
   }

}

or

foo({...default, x:'x', y: 5, z: 0 });
Reza
  • 18,865
  • 13
  • 88
  • 163
  • You can probably do something with decorators here but I am not really sure it's going to be much less boilerplate than `foo({...default, x:'x', y: 5, z: 0 });`. Maybe slightly more reusable, though. – VLAZ May 28 '20 at 16:39

3 Answers3

2

For merge, u need to use merge using de-structure. default assignment will not work here. The default assignment is for work only if the object is undefined while passing value. So you need to merge the default value with passed value.

Please check comment in code.

interface Foo {
  x: string;
  y: number;
  z: number;
  m?: string;
  n?: number;
  o?: number;
}
const defaultValue = { m: "M", n: 10, o: 6 } as Foo;
class A {
  public foo(props: Foo) {
    const { x, y, z, m, n } = { ...defaultValue, ...props };
    console.log(x, y, z, m, n);
  }
  public foo2({ x, y, z, m = defaultValue.m, n = defaultValue.n }: Foo) {
    // this will work, but verbose
    console.log(x, y, z, m, n);
  }
  public foo1({ x, y, z, m, n }: Foo = defaultValue) {
    // this will work only if foo1 called without argument
    console.log(x, y, z, m, n);
  }
  public print() {
    this.foo({ x: "x", y: 5, z: 0 }); // x 5 0 M 10
    this.foo1(); // undefined undefined undefined 'M' 10
    this.foo1({ x: "x", y: 5, z: 0 }); // x 5 0 undefined undefined
    this.foo2({ x: "x", y: 5, z: 0 }); // x 5 0 M 10
  }
}
const a = new A();
a.print();

foo and foo2 function will work. However, foo2 is very verbose if more then few arguments. Use Object.assign() or {...} to merge value.

xdeepakv
  • 7,835
  • 2
  • 22
  • 32
1

You can just add a default value in the parameter itself like below:

public foo({x, y, z , m = 'a' , n = 10} = {x:string, y: number, z: number, m?:string, n?:number}) {
}

If you pass a value, default value will be overridden. With this way, you dont even need an if to check the presence of the value.

and you can still call the method as:

foo({...default, x:'x', y: 5, z: 0 });

Vishal Sharma
  • 316
  • 1
  • 8
0

How about combining and destructing object inside function?

type someType = {x:string, y: number, z: number, m?:string, n?:number};
const initialValues = { m : 'M', n :10, o:6 }

function foo(obj: someType) {
  const {x, y, z , m , n} = {
    ...initialValues,
    ...obj
  }

}
Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50