@igorskyflyer/unite
v1.1.0
Published
Zero-dependency TypeScript library for deriving a union type, a type guard, and an array validator from a single source array.
Downloads
23
Maintainers
Readme
Table of Contents
- ✨ Features
- 🕵🏼 Usage
- 🤹🏼 API
- 🗒️ Examples
- ⚙️ Implementation
- 🎯 Motivation
- 📝 Changelog
- 🪪 License
- 💖 Support
- 🧬 Related
- 👨🏻💻 Author
Features
- ✅ Generates a literal union type from one array, no
as constrequired - 🛡️ Runtime validator included, checks values against the exact same source array
- 📦 One declaration powers the type, the guard and the raw values list
- 🔒 Compile-time error blocks widened
string[]inputs before they cause bugs - 🧊 Source array frozen internally, prevents accidental mutation after creation
- 🔍 Array validator built in, checks whole lists against the allowed set
- 🪶 Zero dependencies, tiny footprint
- 🎯 Full TypeScript autocomplete on valid values
- ⚡ Negligible runtime cost, validation stays as fast as a plain
includes()check - 🧩 Fits any project needing a single source of truth for allowed string values
Usage
Install it by executing any of the following, depending on the preferred package manager:
bun add @igorskyflyer/unitepnpm add @igorskyflyer/uniteyarn add @igorskyflyer/unitenpm i @igorskyflyer/uniteAPI
union(allowedValues)
function union<const T extends readonly string[]>(allowedValues: T): UnionValidator<T>Derives a literal union type and a matching runtime validator from a single array of allowed string values.
The array should be passed as a literal, or as a value typed with as const, so that TypeScript can infer its literal element types rather than widening them to string. Passing a variable explicitly typed as string[] is rejected at compile time.
UnionValidator<T>
interface UnionValidator<T extends readonly string[]>The interface returned by union(). Exported to allow explicit type annotations on exported variables when isolatedDeclarations is enabled in project's tsconfig.json.
.isValid(value)
isValid(value: unknown): value is T[number]Checks whether a single value belongs to the allowed set.
Acts as a TypeScript type guard: when it returns true, value is narrowed to the literal union type derived from the allowed values.
.isValidArray(value)
isValidArray(value: unknown): value is T[number][]Checks whether every element of an array belongs to the allowed set.
Acts as a TypeScript type guard: when it returns true, value is narrowed to an array of the literal union type derived from the allowed values. Returns false if value is not an array. Returns true for an empty array.
.values
readonly values: TThe original array of allowed values, frozen and returned as-is.
Mutating the array originally passed to union() has no effect on this property or on the validator's behavior.
ExtractUnion<T>
type ExtractUnion<T extends { _type: unknown }> = T['_type']Extracts the literal union type from a UnionValidator<T> instance returned by union().
Examples
Basic Usage
import { union, type ExtractUnion } from '@igorskyflyer/unite'
const resourceType = union(['script', 'style'])
type ResourceType = ExtractUnion<typeof resourceType>
// "script" | "style"
resourceType.isValid('script')
// true
resourceType.isValid('link')
// false
resourceType.isValidArray(['script', 'style'])
// true
resourceType.values
// readonly ["script", "style"]Type Narrowing
// Narrowing unknown input, e.g. parsed JSON or a config value.
function handle(input: unknown) {
if (resourceType.isValid(input)) {
// input: "script" | "style" here, not string
}
}Usage with --isolatedDeclarations
import { union, type UnionValidator } from '@igorskyflyer/unite'
const allowed = ['script', 'style'] as const
export const resourceType: UnionValidator<typeof allowed> = union(allowed)
// usage when `isolatedDeclarations` is enabled in project's TSConfigImplementation
union() uses a const type parameter to infer the literal union directly from the array passed in, without requiring as const. A conditional type rejects, at compile time, any input whose element type has already widened to string, for example, a variable declared as string[] before being passed in.
The original array is copied and frozen internally before being returned via .values, so mutating the caller's original array after the validator is created has no effect on the validator's behavior.
.isValid() and .isValidArray() perform the actual runtime check, using Array.prototype.includes and Array.prototype.every respectively against the frozen array. No property named _type exists on the returned object at runtime; it is declared only in the TypeScript interface, for ExtractUnion to read at the type level.
Motivation
Deriving a literal union type and a matching runtime validator from the same array is a common requirement, usually solved by hand with as const plus a separately written type guard. This pattern is prone to drift: the array, the type, and the guard can fall out of sync without a compile error, particularly when the array is declared with an explicit string[] annotation instead of a literal.
unite collapses this into a single declaration, so the type, the guard, and the original values all derive from one source array.
Changelog
Read about the latest changes in the CHANGELOG.
License
Licensed under the MIT license.
Support
Related
A utility that lets you manipulate HTML elements, their attributes and innerHTML as strings, on the go and then render the modified HTML. Very useful in SSG projects.
🔦 Provides frequently used types for your TypeScript projects. 🦄
🎨 Provides common Color-related TypeScript types. 🌈
🧰 Determines whether a given value can be a valid file/directory name. 🏜
@igorskyflyer/vscode-folderpicker
✨ Fast, custom cross-platform folder picker and creator for VS Code with icons, validation, and instant navigation. 🎨
Author
Created by Igor Dimitrijević (igorskyflyer), a senior full-stack software engineer and freelance architect.
