Reusable utility types missing from TypeScript core library. Enjoy!
/**
* The MIT License (MIT)
*
* Copyright (c) 2021 Zachary Gover
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/** Any type of object record with string index types */
export type AnyProps = Record<string, unknown>
/** Dictionary collection with string index types (optionally specify value by setting T) */
export type Dictionary<T = unknown> = Record<string, T>
/** Dictionary collection optionally specify values to T */
export type EmptyObj<K extends keyof any = PropertyKey> = Record<K, never>
/** Type safe object "{}" record (optionally specify index type) */
export type AnyObj<K extends PropertyKey = PropertyKey> = Record<K, unknown>
/** Record with only readonly properties */
export type ReadonlyRecord<K extends keyof any, T> = Readonly<Record<K, T>>
/** From T, make all top level keys mutable (removes readonly) */
export type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
/** From T, make all keys mutable including nested objects/arrays (removes readonly) */
export type DeeplyMutable<T> = {
-readonly [P in keyof T]: (T[P] extends ReadonlyArray<infer U> ? DeeplyMutable<U>[] : DeeplyMutable<T[P]>)
}
/** From T, require properties whose keys are in union K (make specific keys required) */
export type PartRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
/** From T, make properties partial whose keys are in union K (Make specific keys optional) */
export type PartPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
/** From T, extract keys whose types are required (excludes optional properties) (optionally narrow keys in union by specifying K) */
export type RequiredKeysOnly<T, K extends keyof T = keyof T> = {
[P in K]-?: (Pick<T, P> extends AnyObj ? never : P)
}[K]
/** From T, extract keys whose types are optional (excludes required properties) (optionally narrow keys in union by specifying K) */
export type PartialKeysOnly<T, K extends keyof T = keyof T> = {
[P in K]-?: (Pick<T, P> extends AnyObj ? P : never)
}[K]
/** From T, pick a set of properties whose keys are in the union with required keys only, (optionally narrow results by specifying K) */
export type PickRequiredOnly<T, K extends keyof T = keyof T> = Pick<T, {
[P in K]-?: (Pick<T, P> extends AnyObj ? never : P)
}[K]>
/** From T, pick a set of properties whose keys are in the union with partial keys only, (optionally narrow results by specifying K) */
export type PickPartialOnly<T, K extends keyof T = keyof T> = Pick<T, {
[P in K]-?: (Pick<T, P> extends AnyObj ? P : never)
}[K]>
/** From T, rename a property whose key is in the union K (old key) with that of U (new key) */
export type RenameKey<T, K extends keyof T, U extends string> = (Omit<T, K> & { [P in U]: T[K] })
/** With L (left), spread properties with R (right) (e.g. [...L, ...R], {...L, ...R}) */
export type Spreaded<L, R> = (
/* With L (left), omit keys not in union with keys of R (right)*/
Omit<L, keyof R>
/* With R (right), omit keys in union with partial types*/
& Omit<R, PartialKeysOnly<R>>
/* With R (right), pick properties in union with partial types that do not exist in L (left)*/
& Pick<R, Exclude<PartialKeysOnly<R>, keyof L>>
/* With L (left), replace properties of the keys in union with the keys in R (right) excluding properties of R (right) with types in union with undefined */
& { [P in (PartialKeysOnly<R> & (keyof L extends (keyof L & keyof R) ? (PartialKeysOnly<R> & keyof L) : never))]: (L[P] | Exclude<R[P], undefined>) }
)
/// Spreaded usage example
/// const spread = <L, R>(left: L, right: R): Spreaded<L, R> => ({...left, ...right})
/// spread({a: 1, b: 2, d: 5}, {a: 3, b: 2, c: 4, d: undefined})
/// {"a":3,"b":2,"c":4,"d":undefined}
/** Implements a toString method */
export interface StringLike {
toString(): string
[Symbol.toStringTag]?(): string
}