From 0d9846c4622f1908ff057ba2cc6c7d202bb3127e Mon Sep 17 00:00:00 2001 From: Patrick Keenan Date: Fri, 26 May 2023 00:35:46 -0700 Subject: [PATCH] feat(object/types): init - `Key` is a valid object key. - `Entry` is a key-value tuple. - `Pair` is a key-value pair in an object. - `EntryToPair` converts an `Entry` to a `Pair` - `FromEntries` converts `Entry`s to an object - `ToEntries` converts an object to an array of `Entry`s - The `Obj` namespace clusters these helper types. --- object/mod.ts | 1 + object/types.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 11 +++++++++ 3 files changed, 71 insertions(+) create mode 100644 object/types.ts diff --git a/object/mod.ts b/object/mod.ts index 0e556c4..b47e50e 100644 --- a/object/mod.ts +++ b/object/mod.ts @@ -1 +1,2 @@ +export * from "./types.ts"; export * from "./utils.ts"; diff --git a/object/types.ts b/object/types.ts new file mode 100644 index 0000000..3592382 --- /dev/null +++ b/object/types.ts @@ -0,0 +1,59 @@ +import { Pretty } from "../ts/types.ts"; + +/** A valid object key. */ +export type Key = string | number | symbol; + +/** A key-value tuple. Similar to the outputs of `Object.entries` and + * the inputs to `Object.fromEntries`, except numbers are not stringified + * and symbols are allowed. This is primarily used for `extends` clauses + * to ensure that an input conforms to this shape. + * + * @example + * type MyEntry = Obj.Entry; // [Obj.Key, unknown] */ +export type Entry = [key: Key, value: V]; + +/** An object intended to house a single key-value pair. The object-shaped + * equivalent of `Obj.Entry`. Mostly the same as TS's builtin `Record` type + * but provided here for parity with other object types. + * + * @example + * type MyPair = Obj.Pair<"a", 1>; + * // { a: 1 } */ +export type Pair = Pretty<{ [_ in K]: V }>; + +/** Converts an `Obj.Entry` to an `Obj.Pair`. + * + * @example + * type MyPair = Obj.EntryToPair<["a", 1]>; + * // { a: 1 } */ +export type EntryToPair = T extends + [infer K extends Key, infer Value] ? Pair + : never; + +type _EntriesToObject = T extends [] ? Record + : T extends [infer Head extends Entry, ...infer Tail extends Entry[]] + ? EntryToPair & _EntriesToObject + : never; + +/** Converts an array of `Obj.Entry`s to an object. Analogous to + * `Object.fromEntries`. + * + * @example + * type MyObj = Obj.FromEntries<[["a", 1], ["b", 2]]>; + * // { a: 1, b: 2 } */ +export type FromEntries = Pretty<_EntriesToObject>; + +/** Convert an object to an array of `Obj.Entry`s. Unfortunately, this + * cannot return a tuple which would preserve the order of the keys, due to + * current limitations in TypeScript. + * + * @example + * type MyEntries = Obj.ToEntries<{ a: 1, b: 2 }>; + * // Array<["a", 1], ["b", 2]> */ +export type ToEntries = { + [K in keyof T]: [K, T[K]]; +}[keyof T][]; + +export declare namespace Obj { + export { Entry, EntryToPair, FromEntries, Key, Pair, ToEntries }; +} diff --git a/readme.md b/readme.md index e72edd9..788e2bd 100644 --- a/readme.md +++ b/readme.md @@ -242,6 +242,17 @@ const S = Symbol("symbol"); setNestedEntry({}, ["a", 10, S], "👋"); // { a: { 10: { [S]: "👋" } } } ``` +```ts +import type { Obj } from "https://deno.land/x/handy/object/types.ts"; + +type Key = Obj.Key; // string | number | symbol +type Entry = Obj.Entry; // [Key, any] +type Pair = Obj.Pair<"a", number>; // { "a": number } +type EntryToPair = Obj.EntryToPair; // Pair +type MyObj = Obj.FromEntries<[["a", 1], ["b", null]]>; // { a: 1, b: null } +type Entries = Obj.ToEntries; // Array<["a", 1], ["b", null]> +``` + ## `os` OS-related utilities.