Search code examples
typescriptinterface

Typescript: making interface parameters optional when passing to a function


I have a typescript function, that accepts an options object as a parameter. I have an interface that defines the options. I also have a constant that contains default values for every option. It looks something like this:

interface Options {
  viewportHeight: number
  viewportWidth: number
  // ...
}

const defaults: Options = {
  viewportHeight: 600,
  viewportWidth: 600,
// ...
}

function createGenerator(options: Options) {
  options = { ...defaults, ...options }

  return function generate() {
    // Simplfied
    return {
      value: Math.min(options.viewportWidth, options.viewportHeight),
    }
  }
}

The problem is the following: if I leave all properties of the Options interface requires, then I can't do something like createGenerator({ viewportWidth: 50 }) to set only the options I need and leave the rest by default

If I do make them optional, then all options like options.viewportWidth have the type of number | undefined which causes an error Argument of type 'number | undefined' is not assignable to parameter of type 'number' when I'm trying to use them.

I could define two interfaces like Options and FilledOptions, but that's not DRY. Is there some nice way around it?


Solution

  • You can use Partial to make all members of a type optional. You will however need to use a different variable for the final parameters, as TS will just take the assigned type and complain that properties may be undefined

    interface Options {
      viewportHeight: number
      viewportWidth: number
      // ...
    }
    
    const defaults: Options = {
      viewportHeight: 600,
      viewportWidth: 600,
    // ...
    }
    
    function createGenerator(_options: Partial<Options>) {
      const options = { ...defaults, ..._options }
    
      return function generate() {
        // Simplfied
        return {
          value: Math.min(options.viewportWidth, options.viewportHeight),
        }
      }
    }
    
    createGenerator({ viewportWidth: 50 })
    
    

    Play