type-fest icon indicating copy to clipboard operation
type-fest copied to clipboard

Proposal Inferred Partial type

Open Hideman85 opened this issue 3 years ago • 2 comments

I have really no idea how to call this helper, but let me describe the use case.

// Lets imagine I have an options type
type Options {
  readOnly?: boolean;
  required?: boolean;
  filters?: Record<string, string>;
  // ...
}

// Now lets see how I can use in a function
const buildOptions(required: boolean, name: string, team?: string) => {
  const options: Options = {
     required,
     filters: {
       name,
     },
   };
   
   if (team) {
     // Issue is that filters even if defined above remains optional/partial
     options.filters.team = team;
   }
}

// Today we could manuall build the correct type as
const options: Options & Pick<Required<NonNullable<Options>>, 'required' | 'filters'> = {...}

// Issue is when adding more property you always need to add the property in the list
// I tried the following without success to infer the type without explicitely giving the keys
export const makeInferredPartial = <Base, Real extends Required<NonNullable<Base>>>(
  // partial: {[Key in keyof Base]: Required<NonNullable<Base>>[Key]} extends infer Return ? Partial<Base> & Return : never,
  partial: Real,
) => partial;

const options = makeInferredPartial<Options>({
  filters: { name: 'Hello world' },
})
// Would expect the type to be like
{
  readOnly?: boolean;
  required?: boolean;
  filters: Record<string, string>; // Note it become defined
  // ...
}
// Then the following works
options.filters.team = 'admin';

Please let me know if that make sense and if you could help me to build this helper. I think this become pretty useful when the type has plenty of props and you just want to define them and infer the correct typing.

Thanks in advance for your help.

Hideman85 avatar Sep 09 '22 09:09 Hideman85

Can't you just let options be typed automatically, and enforce the return type of your buildOptions function instead?

function buildOptions(required: boolean, name: string, team?: string): Options {
  const options = {
     required,
     filters: {
       name,
     },
   };
   
   if (team) {
     options.filters.team = team;
   }

   return options;
}

papb avatar Sep 20 '22 21:09 papb

In this way you do not get the other properties neither the real type of them 'foo' | 'bar' !== string.

Hideman85 avatar Sep 21 '22 07:09 Hideman85