Skip to content

Instantly share code, notes, and snippets.

@hmmhmmhm
Created September 15, 2020 11:38
Show Gist options
  • Select an option

  • Save hmmhmmhm/62bde54d64feb507150a31ff12c95cdd to your computer and use it in GitHub Desktop.

Select an option

Save hmmhmmhm/62bde54d64feb507150a31ff12c95cdd to your computer and use it in GitHub Desktop.
타입스크립트로 인터페이스 속성에서 꼭 하나는 주어져야하는, 또는 꼭 하나만 주어져야하는 타입 만드는 방법
interface ITestObject {
a: string
b: number
c: Function
d: string[]
}
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>>
& {
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
}[Keys]
type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
Pick<T, Exclude<keyof T, Keys>>
& {
[K in Keys]-?:
Required<Pick<T, K>>
& Partial<Record<Exclude<Keys, K>, undefined>>
}[Keys]
let needToBeLeastOne: RequireAtLeastOne<ITestObject> = {a: ''}
let needToBeOnlyOne: RequireOnlyOne<ITestObject> = {a: ''}
@hm-lee

hm-lee commented Feb 26, 2021

Copy link
Copy Markdown

typescript object conditional optional property type

type RemoveCommonValues<T, TOmit> = {
  [P in keyof T]: TOmit extends Record<P, infer U> ? Exclude<T[P], U> : T[P];
};
type Id<T> = {} & { [P in keyof T]: T[P] }; // flatens out the types to make them more readable can be removed
type ConditionalProps<T, TKey extends keyof TCase, TCase extends Partial<T>> =
  | Id<Omit<T, keyof TCase> & TCase>
  | Id<RemoveCommonValues<T, Pick<TCase, TKey>>>;

type Button = ConditionalProps<
  {
    size: "small" | "large";
    appearance: "solid" | "outline" | "minimal";
    isDisabled?: boolean;
  },
  "appearance" | "size",
  | {
      appearance: "outline";
      size: "small";
      isDisabled: false;
      hasFancyOutline?: boolean;
    }
  | {
      appearance: "minimal";
      size: "small";
      isDisabled: false;
      hasFancyOutline?: boolean;
    }
>;

//  same as
// type Button =
//   | {
//       appearance: "outline";
//       size: "small";
//       isDisabled: false;
//       hasFancyOutline?: boolean | undefined;
//     }
//   | {
//       appearance: "minimal";
//       size: "small";
//       isDisabled: false;
//       hasFancyOutline?: boolean | undefined;
//     }
//   | {
//       size: "large";
//       appearance: "solid";
//       isDisabled?: boolean | undefined;
//     };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment