Using named parameters JavaScript (based on typescript)

Anonymous interface

I just wanted to note that you can also declare the types without a name inside the argument list as follows, which saves us from typing interface myfuncArgs.

It still forces me to retype every single parameter which is a pain, but I don't know how to avoid that for now.

const assert = require('assert')

function myfunc({
    myInt,
    myString,
  }: {
    myInt: number,
    myString?: string,
  }
) {
  return `${myInt} ${myString}`
}

assert.strictEqual(
  myfunc({
    myInt: 1,
    myString: 'abc',
  }),
  '1 abc'
)

assert.strictEqual(
  myfunc({
    myInt: 1,
  }),
  '1 undefined'
)

// Fails as desired since myInt is not optional and was not given.
//assert.strictEqual(
//  myfunc({
//    myString: 'abc',
//  }),
//  'unefined abc'
//)

// Fails as desired since wrong type of myInt.
//assert.strictEqual(
//  myfunc({
//    myInt: '1',
//    myString: 'abc',
//  }),
//  '1 abc'
//)

Compile and run:

npx tsc main.ts
node main.js

Tested on:

  "dependencies": {
    "@types/node": "^16.11.13",
    "typescript": "^4.5.4"
  }

Related:

  • Destructure a function parameter in Typescript

  • https://github.com/Microsoft/TypeScript/issues/29526 feature request to allow the syntax:

    function myfunc({
      myInt: Number,
      myString?: String,
    })
    

You generally want an explicit interface when there are optional parameters

If any of the props is optional, is the case of the following example, and likely of most "options" params, then you likely want to explicitly define the type as mentioned at: https://stackoverflow.com/a/42108988/895245 because it is likely that the caller will need it sooner or later to build the options object step by step, related: How do I dynamically assign properties to an object in TypeScript?

E.g. consider the following working code:

const assert = require('assert')

interface myfuncOpts {
  myInt: number,
  myString?: string,
}

function myfunc({
  myInt,
  myString,
}: myfuncOpts) {
  return `${myInt} ${myString}`
}

const opts: myfuncOpts = { myInt: 1 }
if (process.argv.length > 2) {
  opts.myString = 'abc'
}

assert.strictEqual(
  myfunc(opts),
  '1 abc'
)

If we had defined myfuncOpts inline, then we wouldn't be able to do const opts: myfuncOpts, and then opts.myString = 'abc' would fail because in:

const opts = { myInt: 1 }
if (process.argv.length > 2) {
  opts.myString = 'abc'
}

the type of opts is deduced from the initialization, which does not contain myString.

I wish TypeScript would implement a system where you can say "use the type of such argument of such function". Then we could use inline argument type definitions, but still refer to the type somehow, it would be Nirvana.


The only to get something close to "named parameters" is to use a single object parameter:

type SomeFunctionParams = {
    name1: boolean;
    name2: boolean;
    name3: boolean;
    name4: boolean;
}

SomeFunction(params: SomeFunctionParams) { ... }

And then:

$(function () {
    SomeFunction({
        name1:false, 
        name2:false, 
        name3:false, 
        name4:true
    });  
});

True named parameters don't exist in JavaScript nor in TypeScript but you can use destructuring to simulate named parameters:

interface Names {
    name1: boolean
    name2: boolean
    name3: boolean
    name4: boolean
}

function myFunction({name1, name2, name3, name4}: Names) {
    // name1, etc. are boolean
}

Notice: The type Names is actually optional. The following JavaScript code (without typing) is valid in TS:

function myFunction({name1, name2, name3, name4}) {
    // name1, etc. are of type any
}