UNPKG

typedash

Version:

modern, type-safe collection of utility functions

67 lines (63 loc) 2.83 kB
import { Get } from 'type-fest'; import { O as ObjectPath } from '../ObjectPath-DtBUgaHp.js'; import '../AnyFunction-DuIh5Fcc.js'; /** * Gets all elements except for head in an array * @example * Tail<[1, 2, 3]>; // [2, 3] */ type Tail<T extends readonly unknown[]> = T extends [unknown, ...infer Rest] ? Rest : never; /** * Returns Tail<T> if first element of T matches P. Somehow resolves issues with * union types, but unsure how; @see {@link https://stackoverflow.com/a/57837897/1105281} */ type TailUnion<P, T extends readonly unknown[]> = T extends readonly unknown[] ? T[0] extends P ? Tail<T> : never : never; /** * Converts a string like "a.b.c" to an array ["a", "b", "c"] */ type PathToStringArray<T extends string> = T extends `${infer Head}.${infer Tail}` ? [...PathToStringArray<Head>, ...PathToStringArray<Tail>] : [T]; /** * For any object, enforces that the keys provided are all present; paths are * expressed as lists of keys in the order you would access them on an object; * for instance, for an object called obj, obj.a.b.c would be represented as * ["a", "b", "c"] * @see RequireKeysDeep for usage */ type RequireKeysDeepArray<TObject, PathsToRequire extends readonly string[]> = TObject extends object ? Omit<TObject, Extract<keyof TObject, PathsToRequire[0]>> & Required<{ [K in Extract<keyof TObject, PathsToRequire[0]>]: NonNullable<RequireKeysDeepArray<TObject[K], TailUnion<K, PathsToRequire>>>; }> : TObject; /** * For any object, enforces that the keys provided are all present; works with * deeply nested syntax, by using period (`.`) as a delimiter. * @example * ```ts * type Foo = { a?: 2, b?: { c?: 3, d: 4 } } * type A = RequireKeysDeep<Foo, "a">; // {a: 2, b?: { c?: 3, d: 4 } } * type B = RequireKeysDeep<Foo, "b">; // {a?: 2, b: { c?: 3, d: 4 } } * type BC = RequireKeysDeep<Foo, "b.c">; // {a?: 2, b: { c: 3, d: 4 } } * type ABC = RequireKeysDeep<Foo, "a" | "b.c">; // {a: 2, b: { c: 3, d: 4 } } * ``` */ type RequireKeysDeep<TObject extends object, TPath extends string> = RequireKeysDeepArray<TObject, PathToStringArray<TPath>>; /** * Sets a value at the specified (possibly nested) path in an object. * @template TObject The type of the object. * @template Path The type of the path. * @param object The object to set the value in. * @param path The path to set the value at. * @param value The value to set. * @example * ```ts * const object: { * foo?: { * bar?: { * anArray: string[]; * }; * } * }; * * set(object, 'foo.bar.anArray[0]', 'value'); * object.foo.bar.anArray[0]; // 'value' */ declare function set<TObject extends Record<string, unknown>, Path extends ObjectPath<TObject>>(object: TObject, path: Path, value: Get<TObject, Path>): asserts object is TObject & RequireKeysDeep<TObject, Path>; export { set };