Skip to content

Instantly share code, notes, and snippets.

@brainysmurf
Last active December 25, 2023 03:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brainysmurf/feee30a117a11e6e4df322d9da935c83 to your computer and use it in GitHub Desktop.
Save brainysmurf/feee30a117a11e6e4df322d9da935c83 to your computer and use it in GitHub Desktop.
Named parameters, required parameters, and interfaces

Interfaces in Javascript for Google Apps Scripts

I really like named parameters. I can live without them, but there is one place where I really need them. Cases in which I want to create a class and the paramters are guaranteed to be present, nothing extra. This is one way of implementing them. (It's kinda ugly, but kinda cool.)

Project Key

Either copy into your project, or use as a library: MWzXfEDYTWuJ_Xj0ap9H8-68b30WIDiE_

Wrong behaviour

class Class {
  constructor (one, two) {    
  }
}
// When I initiate a class, I want it to tell me if I have exactly the parameters I need, and no more:
const instance = new Class(/* no params */);
// The above should throw an error because it's expecting one parameter
const instance = new Class(wrong='wrong');
// The above should throw an error because it passed the wrong parameter
const instance = new Class(one='one');
// The above should throw an error not all were passed (missing 'two')
const instance = new Class(two='two', one='one');
// works, but js doesn't have named parameters, so instance.one is 'two' and instance.two is 'one'

Intended correct behaviour

const instance = new Class({one: 'one'});  // throw error "missing param"
const instance = new Class({two: 'two', one: 'one'});  // instance.one is 'one' and instance.two is 'two'
const instance = new Class({three: 'three', one: 'one', two: 'two'});  // throw error "extra param"

How-to

This is how to use the library.

const I = Interface('Test instance', ['one', 'two']);  // Note: parameters here help with error msgs only

// build a class using I
class Test {
  constructor ({one=I.req, two=I.req, ...kwargs}={}) {
    I.extra(kwargs);
  }
}

new Test({more:'more', one: 'one', two:'two'});  // throws error 'extra parameter more'
new Test({one: 'one'}); // throw error 'missing parameter'
new Test({one: 'one', two: 'two'});  // all good
new Test({two: 'two', one: 'one'});  // all good
function Interface (name='', params=[]) {
class I_ {
constructor (n, p) {
this.name = n;
this.params = p;
}
get req() {
throw Error(`Missing at least one required parameter for ${this.name}: ${this.params}`);
}
extra(kwargs) {
if (Object.entries(kwargs).length > 0)
throw Error(`Extra parameters passed to ${this.name}: ${Object.entries(kwargs)}`);
}
}
return new I_(name, params);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment