28143-hard-optionalundefined

Back

type Clean<T> = {
  [key in keyof T]: T[key];
} & {}

type OptionalKeys<T> = {
  [key in keyof T as undefined extends T[key] ? key : never]: T[key]
};

type OptionalUndefined<T, Props extends keyof T = keyof T> = Clean<{
  [key in keyof OptionalKeys<Pick<T, Props>>]?: T[key]
} & Omit<T, keyof OptionalKeys<Pick<T, Props>>>>;

Solution by HiiiiD #33127

type OptionalUndefined<T extends object, Props extends keyof T = keyof T> =
  {
    [K in keyof T as undefined extends T[K] ? K extends Props ? K : never : never]?: T[K]
  } & {
    [K in keyof T as undefined extends T[K] ? K extends Props ? never : K : K]: T[K]
  } extends infer Combined
  ? {[K in keyof Combined]: Combined[K]} : never

Playground

Solution by teamchong #32998

type Copy<T> = {
  [P in keyof T]: T[P];
};
type OptionalUndefined<T, Props extends keyof T = keyof T, All extends keyof T = keyof T> = Copy<
  {
    [P in Props as undefined extends T[P] ? P : never]?: T[P];
  } & {
    [P in Props as undefined extends T[P] ? never : P]: T[P];
  } & {
    [P in Exclude<All, Props>]: T[P]
  }
>;

Solution by Vampirelee #32714

type Merge<T, S> = Omit<Omit<T, keyof S> & S, never>

type OptionalUndefined<T, Props = never> = [Props] extends [never]
  ? Merge<T, { [K in keyof T as undefined extends T[K] ? K : never ]?: T[K] }>
  : Merge<T, {
    [K in keyof T as Props extends K
      ? undefined extends T[K] ? K : never
      : never
    ]?: T[K]
  }>

Solution by Heonys #32459

type OptionalUndefined<T, Props = unknown> = Omit<
  {
    [K in keyof T as undefined extends T[K]
      ? K extends Props
        ? K
        : never
      : never]?: T[K];
  } & {
    [K in keyof T as undefined extends T[K]
      ? K extends Props
        ? never
        : K
      : K]: T[K];
  },
  never
>;

Solution by vangie #32260

type OptionalUndefined<T, Props extends keyof T = keyof T> = Omit<{
  [P in keyof T as P extends Props ? undefined extends T[P] ? never : P : P]: T[P]
} & {
  [P in keyof T as undefined extends T[P] ? P : never]?: T[P]
}, never>

Solution by preventdefault #31725

type Intersection<A, B> = A & B extends infer I
  ? { [P in keyof I]: I[P] }
  : never;

type OptionalFields<T, Props extends keyof T> = {
  [K in Props]: undefined extends T[K] ? K : never
}[Props];

type OptionalUndefined<T, Props extends keyof T=keyof T> = Intersection<{
  [K in OptionalFields<T, Props>]?: T[K];
}, {
  [K in Exclude<keyof T, OptionalFields<T, Props>>]: T[K];
}>

Solution by sehyod #29970

// your answers
type OptionalUndefinedKey<T, Props extends keyof T> = {
  [K in keyof T]: undefined extends T[K] ? (K extends Props ? K : never) : never
}[keyof T]

type OptionalUndefined<T,
  Props extends keyof T = keyof T,
  OptionalKey extends keyof T = OptionalUndefinedKey<T, Props>
> = Omit<{ [K in Exclude<keyof T, OptionalKey>]: T[K] } & { [K in OptionalKey]?: T[K] }, never>

Solution by venusliang #29829

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

type OptionalObject<T extends object, Props extends keyof T> = {
  [Key in Extract<Props, UndefinedFields<T>>]?: T[Key]
}

type MergeSets<T extends object> = {
  [Key in keyof T]: T[Key]
}

type OptionalUndefined<
  T extends object,
  Props extends keyof T = keyof T,
  U = OptionalObject<T, Props>
> = MergeSets<Omit<T, keyof U> & U>

Solution by simone-paglino #29649

type Copy<T> = {
  [K in keyof T]: T[K]
}

type OptionalUndefined<T, Props extends keyof T = keyof T> = Copy<
  Omit<T, Props> &
  {
    [K in keyof Pick<T, Props> as undefined extends Pick<T, Props>[K] ? never : K]: Pick<T, Props>[K]
  } &
  {
    [K in keyof Pick<T, Props> as undefined extends Pick<T, Props>[K] ? K : never]?: Pick<T, Props>[K]
  } 
>

Solution by XkSuperCool #28451


type GetUndefinedKey<T> = 
keyof { [p in keyof T as undefined extends T[p] ? p : never]: T[p]; }

type OptionalUndefined<
  T, Props extends keyof T = keyof T, 
  U extends keyof T = GetUndefinedKey<T> & Props
> = Omit<Omit<T, U> & Partial<Pick<T, U>>, never>

Solution by omittee #28254

type CombineObj<T extends object> = { [P in keyof T]: T[P] };
type OptionalUndefined<T, Props extends keyof T = keyof T> = CombineObj<
  { [P in keyof T & Props as Equal<Partial<T>[P], T[P]> extends true ? P : never]?: T[P] } &
  { [P in keyof T as Equal<Partial<T>[P], T[P]> extends true ? never : P]: T[P] } &
  { [P in keyof T as P extends Props ? never : P]: T[P] }>;

Solution by E-uler #28246

type OptionalUndefined<T, Props extends keyof T = keyof T> = Omit<
  Omit<T, Props> & {
    [K in Props as undefined extends T[K] ? K : never]?: T[K];
  } & {
    [K in Props as undefined extends T[K] ? never : K]: T[K];
  },
  never
>;

Solution by JohnLi1999 #28206

type Merge<T> = {
  [K in keyof T]:T[K]
}

type OptionalUndefined<
  T, 
  Props extends keyof T = keyof T,
  OptionsProps extends keyof T = 
    Props extends keyof T? 
      undefined extends T[Props]? 
        Props:never 
      :never
> = 
  Merge<{
    [K in OptionsProps]?:T[K]
  } & {
    [K in Exclude<keyof T,OptionsProps>    ]:T[K]
  }>

Solution by jiangshanmeta #28200

type OptionalUndefined<T, Props = keyof T, Keys extends keyof T = GetCanBeUndefinedKeys<T> & Props> = Helper<Partial<Pick<T, Keys>> & Omit<T, Keys>>

type GetCanBeUndefinedKeys<T> = keyof {
  [Key in keyof T as (undefined extends T[Key] ? Key : never)]: any
}

type Helper<T> = {
  [Key in keyof T]: T[Key]
}

Solution by Sun79 #28170