AJP
AJP

Reputation: 28483

Setting default value for TypeScript object passed as argument

function sayName(params: {firstName: string; lastName?: string}) {
    params.lastName = params.lastName || 'smith';  // <<-- any better alternative to this?
    var name = params.firstName + params.lastName
    alert(name);
}

sayName({firstName: 'bob'});

I had imagined something like this might work:

function sayName(params: {firstName: string; lastName: string = 'smith'}) {

Obviously if these were plain arguments you could do it with:

function sayName(firstName: string, lastName = 'smith') {
    var name = firstName + lastName;
    alert(name);
}

sayName('bob');

And in coffeescript you have access to the conditional existence operator so can do:

param.lastName ?= 'smith'

Which compiles to the javascript:

if (param.lastName == null) {
    param.lastName = 'smith';
}

Upvotes: 421

Views: 565456

Answers (9)

dspies
dspies

Reputation: 1543

If you want to use the parameter as an object (not destructured properties), you can also do something like:

// name.ts
interface Name {
  firstName: string; 
  lastName?: string
}

// other-class.ts
const defaultParams: Name = {
  firstName: '',
  lastName: 'Smith'
};

...

sayName(params: Name) {
  const nameWithDefaults: Name = {...defaultParams, ...params};
  console.log(nameWithDefaults);
}

// External caller
sayName({firstName: 'Jane'});   // {firstName: 'Jane', lastName: 'Smith'}

Upvotes: 0

Ankur Sehdev
Ankur Sehdev

Reputation: 136

There is another way without destructuring could be to set the default value with the type like this:

function name(param1:type=defaultValue1, paramr2:type=defaultvalue2,...) {//}

An example could be

function addTwoNumbers(first:number = 1, second:number = 3):number {return first+second}
console.log(addTwoNumbers())

Upvotes: 2

Benson
Benson

Reputation: 4391

Object destructuring the parameter object is what many of the answers above are aiming for and Typescript now has the methods in place to make it much easier to read and intuitively understand.

Destructuring Basics: By destructuring an object, you can choose properties from an object by key name. You can define as few or as many of the properties you like, and default values are set by a basic syntax of let {key = default} = object.

let {firstName, lastName = 'Smith'} = myParamsObject;

//Compiles to:
var firstName = myParamsObject.firstName, 
_a = myParamsObject.lastName, 
lastName = _a === void 0 ? 'Smith' : _a;

Writing an interface, type or class for the parameter object improves legibility.

type FullName = {
  firstName: string;
   
  /** @defaultValue 'Smith' */
  lastName ? : string;
}

function sayName(params: FullName) {

  // Set defaults for parameter object
  var { firstName, lastName = 'Smith'} = params;

  // Do Stuff
  var name = firstName + " " + lastName;
  alert(name);
}

// Use it
sayName({
  firstName: 'Bob'
});

Upvotes: 81

jpadvo
jpadvo

Reputation: 6625

Actually, there appears to now be a simple way. The following code works in TypeScript 1.5:

function sayName({ first, last = 'Smith' }: {first: string; last?: string }): void {
  const name = first + ' ' + last;
  console.log(name);
}

sayName({ first: 'Bob' });

The trick is to first put in brackets what keys you want to pick from the argument object, with key=value for any defaults. Follow that with the : and a type declaration.

This is a little different than what you were trying to do, because instead of having an intact params object, you have instead have dereferenced variables.

If you want to make it optional to pass anything to the function, add a ? for all keys in the type, and add a default of ={} after the type declaration:

function sayName({first='Bob',last='Smith'}: {first?: string; last?: string}={}){
    var name = first + " " + last;
    alert(name);
}

sayName();

Upvotes: 472

Akhil F
Akhil F

Reputation: 7740

Without destructuring, you can create a defaults params and pass it in

interface Name {
   firstName: string;
   lastName: string;
}

export const defaultName extends Omit<Name, 'firstName'> {
    lastName: 'Smith'
}

sayName({ ...defaultName, firstName: 'Bob' })

Upvotes: 1

Ben Dev
Ben Dev

Reputation: 865

Here is something to try, using interface and destructuring with default values. Please note that "lastName" is optional.

interface IName {
  firstName: string
  lastName?: string
}

function sayName(params: IName) {
  const { firstName, lastName = "Smith" } = params
  const fullName = `${firstName} ${lastName}`

  console.log("FullName-> ", fullName)
}

sayName({ firstName: "Bob" })

Upvotes: 6

encrest
encrest

Reputation: 1855

Typescript supports default parameters now:

https://www.typescriptlang.org/docs/handbook/functions.html

Also, adding a default value allows you to omit the type declaration, because it can be inferred from the default value:

function sayName(firstName: string, lastName = "Smith") {
  const name = firstName + ' ' + lastName;
  alert(name);
}

sayName('Bob');

Upvotes: 87

Cameron
Cameron

Reputation: 876

This can be a nice way to do it that does not involve long constructors

class Person {
    firstName?: string = 'Bob';
    lastName?: string = 'Smith';

    // Pass in this class as the required params
    constructor(params: Person) {
        // object.assign will overwrite defaults if params exist
        Object.assign(this, params)
    }
}

// you can still use the typing 
function sayName(params: Person){ 
    let name = params.firstName + params.lastName
    alert(name)
}

// you do have to call new but for my use case this felt better
sayName(new Person({firstName: 'Gordon'}))
sayName(new Person({lastName: 'Thomas'}))

Upvotes: 28

WiredPrairie
WiredPrairie

Reputation: 59763

No, TypeScript doesn't have a natural way of setting defaults for properties of an object defined like that where one has a default and the other does not. You could define a richer structure:

class Name {
    constructor(public first : string, 
        public last: string = "Smith") {

    }
}

And use that in place of the inline type definition.

function sayName(name: Name) {
    alert(name.first + " " + name.last);
}

You can't do something like this unfortunately:

function sayName(name : { first: string; last?:string } 
       /* and then assign a default object matching the signature */  
       = { first: null, last: 'Smith' }) {

} 

As it would only set the default if name was undefined.

Upvotes: 32

Related Questions