/**
 * Common utilities for manipulating TypeScript types.
 * @module
 */

/**
 * Hack! This type causes TypeScript to simplify how it renders object types.
 *
 * It is functionally the identity for object types, but in practice it can
 * simplify expressions like `A & B`.
 */
export type Expand<ObjectType extends Record<any, any>> =
  ObjectType extends Record<any, any>
    ? {
        [Key in keyof ObjectType]: ObjectType[Key];
      }
    : never;

/**
 * Apply `Omit<>` to each element of a union.
 */
export type DistributiveOmit<T, K extends keyof T> = T extends any
  ? Omit<T, K>
  : never;

/**
 * From ObjectType, pick the properties that are assignable to T.
 */
export type PickByValue<ObjectType, T> = Pick<
  ObjectType,
  {
    [Key in keyof ObjectType]: ObjectType[Key] extends T ? Key : never;
  }[keyof ObjectType]
>;

/**
 * Convert a union type like `A | B | C` into an intersection type like
 * `A & B & C`.
 */
export type UnionToIntersection<UnionType> = (
  UnionType extends any ? (k: UnionType) => void : never
) extends (k: infer I) => void
  ? I
  : never;
