Skip to content

Instantly share code, notes, and snippets.

@wmakeev
Last active July 21, 2021 07:46
Show Gist options
  • Save wmakeev/099ae977aa65da3d192e57b169fd1eba to your computer and use it in GitHub Desktop.
Save wmakeev/099ae977aa65da3d192e57b169fd1eba to your computer and use it in GitHub Desktop.
[TypeScript Utility Types] #typescript #tips #cheatsheet #type #utility

Function wrapper

function spreadsheetErrorHandler<T extends (...args: any[]) => any>(
  func: T
): T {
  return <T>function (...args: any[]) {
    try {
      return func(...args)
    } catch (err) {
      if (
        err instanceof SpreadsheetHelper.SpreadsheetHelperError &&
        err.range
      ) {
        throw new CellValueError(err.message, err.range)
      }

      throw err
    }
  }
}

Select nullable keys

export type NullableKeys<T> = {
  [P in keyof T]-?: Extract<T[P], null | undefined> extends never ? never : P
}[keyof T]

type T1 = {
  a: number
  b?: string
  c: boolean | null
  d: string | null | undefined
  e: Date | undefined
  f: null | undefined
  g?: 'foo' | null | undefined
}

type T2 = NullableKeys<T1> // "b" | "c" | "d" | "e" | "f" | "g"

Pick readonly

Warning: This transform lose fields comments

type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X
  ? 1
  : 2) extends <T>() => T extends Y ? 1 : 2
  ? A
  : B

type ReadonlyKeys<T> = {
  [P in keyof T]-?: IfEquals<
    { [Q in P]: T[P] },
    { -readonly [Q in P]: T[P] },
    never,
    P
  >
}[keyof T]

type WritableKeys<T> = {
  [P in keyof T]-?: IfEquals<
    { [Q in P]: T[P] },
    { -readonly [Q in P]: T[P] },
    P
  >
}[keyof T]

Using example:

export type Patch<
  T extends MetaType,
  E = EntityByMetaType[T]
> = Partial<
  {
    [P in WritableKeys<E>]:
      // positions like
      E[P] extends CollectionRef<infer M> | undefined
      ? (Patch<M> & EntityRef<M>)[] | undefined

      // attributes like
      : E[P] extends Array<Entity<infer M>> | undefined
      ? (Patch<M> & EntityRef<M>)[] | undefined

      // Default
      : E[P]
  }
>

Select keys by type

type StringOrNumber = string | number

interface A {
  a: string
  b: number
  c: string[]
  d: Date
}

type SelectKeys<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];

type keys = SelectKeys<A, StringOrNumber> // type keys = "a" | "b"

Substract and Extract

type Substract<T, U> = T extends U ? never : T

type T1 = string | null | undefined

type T2 = Substract<T1, undefined> // string | null

// Buildin
type T3 = Extract<T1, undefined> // undefined
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment