jabuj
jabuj

Reputation: 3639

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?

Upvotes: 1

Views: 756

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249616

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

Upvotes: 5

Related Questions