UNPKG

@stainless-code/layers

Version:

Headless, UI-agnostic layer/stack manager for modal/dialog/drawer/popover/toast UI. Call a layer like an async function and await its response.

73 lines (65 loc) 1.9 kB
import type { DefaultLayerError, LayerKey } from "./types"; declare const dataTagSymbol: unique symbol; declare const dataTagErrorSymbol: unique symbol; /** * Phantom-brands a {@link LayerKey} so response and error types survive inference * without runtime metadata. * Tagging is idempotent: the first tag wins, avoiding conflicting brands * intersecting into `never`. */ export type DataTag< Key extends LayerKey, R, E = DefaultLayerError, > = Key extends { [dataTagSymbol]: unknown; [dataTagErrorSymbol]: unknown; } ? Key : Key & { [dataTagSymbol]: R; [dataTagErrorSymbol]: E; }; /** Lets generic APIs recover the response associated with a tagged key. */ export type InferDataTagResponse<Key> = Key extends { [dataTagSymbol]: infer R; } ? R : never; /** Lets generic APIs recover the error associated with a tagged key. */ export type InferDataTagError<Key> = Key extends { [dataTagErrorSymbol]: infer E; } ? E : never; /** * Preserves a response default when a generic key is untagged. */ export type ResponseOf<Key, Fallback = void> = Key extends { [dataTagSymbol]: infer R; } ? R : Fallback; /** Preserves an error default when a generic key is untagged. */ export type ErrorOf<Key, Fallback = DefaultLayerError> = Key extends { [dataTagErrorSymbol]: infer E; } ? E : Fallback; /** * Adds response and error inference to a key without changing it at runtime. * * @example * ```ts * import { LayerClient, layerKey } from "@stainless-code/layers"; * * const client = new LayerClient(); * const removeKey = layerKey<boolean>()(["confirm", "remove"]); * const ok = await client.open({ key: removeKey, payload: { title: "Remove?" } }); * // ^? boolean * ``` */ export function layerKey<R, E = DefaultLayerError>() { return <const Key extends LayerKey>(key: Key): DataTag<Key, R, E> => key as DataTag<Key, R, E>; }