question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot omit optional parameter

See original GitHub issue

Describe the bug When I define an object with optional parameters, I expect the type inferred from the object to allow missing fields.

To Reproduce

import * as yup from 'yup';
import Axios from "axios";

const idSchema = yup.object({
    id: yup.string(),
});

type IdSchema = yup.TypeOf<typeof idSchema>;

interface Id2 {
    id?: string;    
} 

const id1: IdSchema = {};   // Property 'id' is missing in type '{}' but required in type 'TypeOfShape<{ id: StringSchema<string | undefined, Record<string, any>, string | undefined>; }>'
const id2: Id2 = {}; // OK
const id3: IdSchema = { id: undefined };  // OK

Expected behavior allow missing fields. I don’t know if this is expected, but if you have the majority fields of a schema to be optional, it is very verbose to explicitly note them to be undefined

Platform (please complete the following information):

  • Browser [e.g. chrome, safari] node
  • Version [e.g. 22] yup 0.32.8, typescript 4.1.2

Additional context Add any other context about the problem here.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:13
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

11reactions
hanayashikicommented, Jan 6, 2021

I wrote my own type inference compatible with yup 0.32.8:

import * as yup from 'yup';
import { ObjectSchema } from "yup";
import { ObjectShape } from "yup/lib/object";
import { TypedSchema } from "yup/lib/util/types";

export type InferShape<TSchema> =
    TSchema extends ObjectSchema<infer Shape> ? Shape : never;

export type UndefinableKeys<Shape extends ObjectShape> = string & {
    [K in keyof Shape]?:
    Shape[K] extends TypedSchema ?
    undefined extends yup.InferType<Shape[K]> ?
    K : never
    : never;
}[keyof Shape];

export type InferInterfaceFromShape<Shape extends ObjectShape> = {
    [K in UndefinableKeys<Shape>]?: Shape[K] extends TypedSchema ? yup.InferType<Shape[K]> : any;
} & {
        [K in Exclude<keyof Shape, UndefinableKeys<Shape>>]: Shape[K] extends TypedSchema ? yup.InferType<Shape[K]> : any;
    }

export type InferInterface<TSchema> =
    InferInterfaceFromShape<InferShape<TSchema>>;

Now you can omit key in your value against the inferred type:

const person = yup.object({
    firstName: yup.string(),
    lastName: yup.string().defined(),
});

type Shape = InferShape<typeof idSchema2>;

type Interface = InferInterfaceFromShape<Shape>;

const t: Interface = {
    // firstName is optional and omitted
    lastName: "abramov",
};
2reactions
OoDeLallycommented, Mar 8, 2022

My little workaround:


type OmitIfNotOptional<T extends object> = {
  [Key in keyof T as undefined extends T[Key] ? Key : never]: T[Key];
};

type OmitIfOptional<T extends object> = {
  [Key in keyof T as undefined extends T[Key] ? never : Key]: T[Key];
};

// eslint-disable-next-line @typescript-eslint/ban-types
type PassThroughUnion = String | Number | Date | Function | RegExp; // May be completed with other builtin classes.

export type MakeUndefinableFieldsOptional<
  T,
  ExtraPassThroughTypes = never,
> = T extends PassThroughUnion | ExtraPassThroughTypes
  ? T
  : T extends (infer E)[]
  ? MakeUndefinableFieldsOptional<E>[]
  : T extends object
  ? {
      [Key in keyof OmitIfOptional<T>]: MakeUndefinableFieldsOptional<T[Key]>;
    } & {
      [Key in keyof OmitIfNotOptional<T>]?: MakeUndefinableFieldsOptional<
        T[Key]
      >;
    }
  : T;


export type User = MakeUndefinableFieldsOptional<
  yup.InferType<typeof userYup>,
  OptionallyOtherTypesThatMayBeIgnored
>;

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to pass optional parameters while omitting some other ...
The question is, as I see it, how one can bypass/skip several optional parameters and set only specific ones. country isn't required, it's...
Read more >
Omit one optional parameter while providing another in TS
To omit one optional parameter, while providing another in a TypeScript function, pass an undefined value for the optional parameter you want to...
Read more >
Named and Optional Arguments - C# Programming Guide
Named and optional arguments enable you to omit the argument for an optional parameter if you don't want to change the parameter's default...
Read more >
Chapter 4 Labeled arguments - OCaml
Note that if that argument is labeled, you will only be able to eliminate optional arguments by totally applying the function, omitting all...
Read more >
Optional Parameters - TADS
If the caller supplies a value for an optional parameter, the value is assigned to the parameter variable as usual. But if the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found