Search code examples
reactjstypescriptreact-typescripttyping

How to type named, optional parameter that accepts an object with optional fields that have defaults in TypeScript-React?


I want something like the style prop in the default HTML components:

 <div ref={ref} style={{ overflow: 'visible', height: 600, width: '100%' }}>

style itself is an optional prop, and the fields inside the object passed to style are optional too (and I assume they have defaults). I wish I could just look at the source code to figure out how it's done, but it just looks like complete gibberish to me.

Stuff I tried

function a({
  param1 = 'default param1',
  options = { option1: 'default option1', option2: 'default option2' },
}: {
  param1?: string;
  options?: { option1?: string; option2?: string };
}) {
  console.log(param1);
  console.log(options);
}

a({});
a({ param1: 'my param1' });
a({ param1: 'my param1', options: { option1: 'my option1' } });
[LOG]: "default param1" 
[LOG]: {
  "option1": "default option1",
  "option2": "default option2"
} 
[LOG]: "my param1" 
[LOG]: {
  "option1": "default option1",
  "option2": "default option2"
} 
[LOG]: "my param1" 
[LOG]: {
  "option1": "my option1"
} 

This almost works but the default for options is overridden completely when I only pass in option1. How do I set defaults for each field in options individually?


Solution

  • You can do something along these lines if you only care about individual options:

    function a({
      param1 = 'default param1',
      options,
    }: {
      param1?: string;
      options?: { option1?: string; option2?: string };
    }) {
      const {option1 = 'default option1', option2 = 'default option2'} = options ?? {}
      console.log(param1);
      console.log({option1, option2});
    }
    

    Alternatively, you could use Object.assign to build your options objects, e.g.

    const defaultOptions = {
       option1: 'default option1', 
       option2: 'default option2'
    }
    function a({
      param1 = 'default param1',
      options,
    }: {
      param1?: string;
      options?: { option1?: string; option2?: string };
    }) {
      const effectiveOptions = Object.assign({}, defaultOptions, options)
      console.log(param1);
      console.log(effectiveOptions);
    }